Using font sizes in a loop - java

I am trying to write a program that displays a phrase in every font size from 6 - 20. I created a for loop to increase the font size and the y axis for each time the phrase is displayed. However, when I run the program it only shows the phrase once at font size 20... what am I missing?
import javax.swing.*;
import java.awt.*;
public class JFontSizes extends JFrame
{
String phrase = new String("This is a phrase in every font size from 6 through 20!");
int font = 6;
int y = 100;
public JFontSizes()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics gr)
{
while(font < 21)
{
super.paint(gr);
Font timesPlain = new Font("Times New Roman",Font.PLAIN, font);
gr.setFont(timesPlain);
gr.drawString(phrase, 60, y);
font++;
y = y + 1;
}
}
public static void main(String[]args)
{
JFontSizes frame = new JFontSizes();
frame.setSize(550,550);
frame.setVisible(true);
}
}

Don't call the super paint method within the while loop as it's erasing the previously drawn Strings. Call it before the loop.
Other issues:
Never draw within a JFrame as you're doing.
Instead draw within the paintComponent method of a JPanel.
And same as noted above, call the super.paintComponent(g) before the while loop.
And then display the JPanel in your JFrame.
Make font and y a local variable of the method. You want them reset each time a repaint is performed.
e.g.,
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class FontSizes extends JPanel {
private static final String PHRASE = new String("This is a phrase "
+ "in every font size from 6 through 20!");
private static final int PREF_W = 500;
private static final int PREF_H = 400;
private static final int GAP = 8;
private static final int STARTING_FONT_PTS = 6;
private static final int MAX_FONT_PTS = 21;
private static final Font STARTING_FONT = new Font("Times New Roman",
Font.PLAIN, STARTING_FONT_PTS);
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// let's make fonts appear smoother
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
int fontPoints = STARTING_FONT_PTS;
int y = GAP;
Font font = STARTING_FONT;
while (fontPoints < MAX_FONT_PTS) {
g.setFont(font);
// let's space lines based on font height
y += g.getFontMetrics().getAscent() + GAP;
g.drawString(PHRASE, GAP, y);
fontPoints++;
font = font.deriveFont((float) fontPoints);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("FontSizes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new FontSizes());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Related

Painting on a class extending JFrame in Java

i'm kind of new with Java graphics, i'm trying to create a simple crossroad GUI interface with 4 traffic lights on it, when using the following classes that I have created - I get a window with a large grey rectangle on it (I assume that since I didn't allocate a traffic lights in the center it has been filled with the default grey background), how do I control the size of the center of the JFrame?
This is what i'm looking to acheive:
This is what i'm getting:
This is the JFrame class.
import java.awt.*;
import javax.swing.*;
public class CrossroadInterface extends JFrame /*implements IAppInterface*/ {
private static final int WIDTH_OF_WINDOW = 400;
private static final int HEIGHT_OF_WINDOW = 400;
//Panels
TrafficLight tLightW, tLightC, tLightE, tLightS, tLightN;
//Other
public CrossroadInterface() {
super("My Crossroad");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(WIDTH_OF_WINDOW, HEIGHT_OF_WINDOW);
this.setVisible(true);
createInterface();
}
public void createInterface () {
tLightW = new TrafficLight();
tLightE = new TrafficLight();
tLightS = new TrafficLight();
tLightN = new TrafficLight();
this.add(tLightW, BorderLayout.WEST);
this.add(tLightN, BorderLayout.NORTH);
this.add(tLightE, BorderLayout.EAST);
this.add(tLightS, BorderLayout.SOUTH);
}
}
This is the Jpanel class.
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TrafficLight extends JPanel {
private final Color offRed = new Color(128, 0, 0);
private final Color offGreen = new Color(0, 96, 0);
private static final int CAR_DIAMETER = 50;
private static final int PERSON_HEIGHT = 100;
private static final int PERSON_WIDTH = 50;
private int status;
public TrafficLight() {
super();
this.setSize(CAR_DIAMETER, 120);
this.setBackground(Color.BLACK);
status = 0;
this.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(offRed);
g.fillOval(this.getX(), this.getY(), CAR_DIAMETER, CAR_DIAMETER);
g.setColor(offGreen);
g.fillOval(this.getX(), this.getY()+CAR_DIAMETER, CAR_DIAMETER, CAR_DIAMETER);
g.setColor(offRed);
g.fillRect(this.getX(), this.getY()+CAR_DIAMETER+PERSON_HEIGHT, PERSON_WIDTH, PERSON_HEIGHT);
g.setColor(offGreen);
g.fillRect(this.getX(), this.getY()+CAR_DIAMETER+2*PERSON_HEIGHT, PERSON_WIDTH, PERSON_HEIGHT);
//drawIlluminatedLights(g);
System.out.println(this.getX()+" "+this.getY());
}
}
EDIT:
Following Hovercraft Full Of Eels' advise, here are my new classes:
import java.awt.*;
import javax.swing.*;
public class CrossroadInterface extends JFrame /*implements IAppInterface*/ {
private static final int WIDTH_OF_WINDOW = 900;
private static final int HEIGHT_OF_WINDOW = 900;
//Panels
TrafficLight tLightW, tLightC, tLightE, tLightS, tLightN;
//Other
public CrossroadInterface() {
super("My Crossroad");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(WIDTH_OF_WINDOW, HEIGHT_OF_WINDOW);
setLayout(new GridLayout(3,3));
createInterface();
}
public void createInterface () {
tLightW = new TrafficLight();
tLightE = new TrafficLight();
tLightS = new TrafficLight();
tLightN = new TrafficLight();
this.add(new JPanel());
this.add(tLightW);
this.add(new JPanel());
this.add(tLightN);
this.add(new JPanel());
this.add(tLightE);
this.add(new JPanel());
this.add(tLightS);
this.setVisible(true);
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
public class TrafficLight extends JPanel {
private final Color offRed = new Color(128, 0, 0);
private final Color offGreen = new Color(0, 96, 0);
private static final int CAR_DIAMETER = 50;
private static final int PERSON_HEIGHT = 50;
private static final int PERSON_WIDTH = 50;
private int status;
public TrafficLight() {
super();
status = 0;
this.setPreferredSize(new Dimension(CAR_DIAMETER,2*CAR_DIAMETER+2*PERSON_HEIGHT));
this.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(offRed);
g.fillOval(100, 50, CAR_DIAMETER, CAR_DIAMETER);
g.setColor(offGreen);
g.fillOval(100, 50+CAR_DIAMETER, CAR_DIAMETER, CAR_DIAMETER);
g.setColor(offRed);
g.fillRect(100, 50+CAR_DIAMETER+PERSON_HEIGHT, PERSON_WIDTH, PERSON_HEIGHT);
g.setColor(offGreen);
g.fillRect(100, 50+CAR_DIAMETER+2*PERSON_HEIGHT, PERSON_WIDTH, PERSON_HEIGHT);
//drawIlluminatedLights(g);
}
}
Your problem is not that the center of the JFrame is too large, but rather it's because the size of your surrounding JPanels are too small. Understand that most Swing layout managers respect a components preferred size, and use this to set the size of the component. Your other problems include
using getX() and getY() to place your drawings. These values give the location of the JPanel within its container, but that won't help you place your drawing since when you draw within the JPanel the drawing's location is placed relative to the location of the pixel within the JPanel not its container, so using these methods will mess you up.
Calling the JFrame's setVisible(true) before adding all components. This risks not displaying all components.
Making your TrafficLight class extend JPanel. You're far better off using a single JPanel to do all the drawing and have your TrafficLight class not extend from any Swing component but rather be a logical class. Give it a public void draw(Graphics2D g2) method that you can call within the drawing JPanel's paintComponent method.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class CrossRoads2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 100;
List<TrafficLight2> lights = new ArrayList<>();
public CrossRoads2() {
// create a timer to randomly change traffic light state
// and start it
new Timer(TIMER_DELAY, new TimerListener()).start();
// create 4 TrafficLight2 objects and place them at 4
// compass locations, and add to lights ArrayList
int x = (PREF_W - TrafficLight2.getWidth()) / 2;
int y = 0;
lights.add(new TrafficLight2(x, y));
x = 0;
y = (PREF_H - TrafficLight2.getHeight()) / 2;
lights.add(new TrafficLight2(x, y));
x = (PREF_W - TrafficLight2.getWidth());
lights.add(new TrafficLight2(x, y));
x = (PREF_W - TrafficLight2.getWidth()) / 2;
y = (PREF_H - TrafficLight2.getHeight());
lights.add(new TrafficLight2(x, y));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// cast g into a Graphics2 object
Graphics2D g2 = (Graphics2D) g;
// for smooth rendering
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through the ArrayList, calling the draw method on each light
for (TrafficLight2 light : lights) {
light.draw(g2);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
// give our JPanel a decent size
return new Dimension(PREF_W, PREF_H);
}
// ActionListener that randomly changes the LightState of each traffic light
private class TimerListener implements ActionListener {
private Random random = new Random();
#Override
public void actionPerformed(ActionEvent e) {
for (TrafficLight2 light : lights) {
// random number 0 to 2
int randomIndex = random.nextInt(LightState.values().length);
// get one of the LightStates using the index above
LightState lightState = LightState.values()[randomIndex];
// set our light to this state
light.setLightState(lightState);
}
repaint();
}
}
private static void createAndShowGui() {
CrossRoads2 mainPanel = new CrossRoads2();
JFrame frame = new JFrame("Cross Roads");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class TrafficLight2 {
private static final int ELLIPSE_W = 40;
private static final int GAP = 4;
private int x;
private int y;
private LightState lightState = LightState.RED; // what color is bright
// map to hold our 3 ellipses, each one corresponding to a LightState
private Map<LightState, Shape> lightMap = new EnumMap<>(LightState.class);
public TrafficLight2(int x, int y) {
// create 3 ellipses, one each for RED, YELLOW, GREEN
// place each one below the previous
// associate each one with one of our RED, YELLOW, or GREEN LightStates
// putting the Ellipse into the map with the light state as key
this.x = x;
this.y = y;
int tempX = x + GAP;
int tempY = y + GAP;
lightMap.put(LightState.RED, new Ellipse2D.Double(tempX, tempY, ELLIPSE_W, ELLIPSE_W));
tempY += ELLIPSE_W + GAP;
lightMap.put(LightState.YELLOW, new Ellipse2D.Double(tempX, tempY, ELLIPSE_W, ELLIPSE_W));
tempY += ELLIPSE_W + GAP;
lightMap.put(LightState.GREEN, new Ellipse2D.Double(tempX, tempY, ELLIPSE_W, ELLIPSE_W));
}
// called by JPanel's paintComponent
public void draw(Graphics2D g2) {
// iterate through the 3 LightStates
for (LightState ltSt : LightState.values()) {
// if the ltSt in the for loop is this traffic light's LightState
// then the display color should be bright
Color c = ltSt == lightState ? ltSt.getColor() :
// other wise the display color should be very dark
ltSt.getColor().darker().darker().darker();
g2.setColor(c);
g2.fill(lightMap.get(ltSt)); // fill the oval with color
g2.setColor(Color.BLACK);
g2.draw(lightMap.get(ltSt)); // draw a black border
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public LightState getLightState() {
return lightState;
}
public void setLightState(LightState lightState) {
this.lightState = lightState;
}
// static method for the width of our traffic lights
public static int getWidth() {
return 2 * GAP + ELLIPSE_W;
}
// static method for the height of our traffic lights
public static int getHeight() {
return 4 * GAP + 3 * ELLIPSE_W;
}
}
// enum that encapsulates the 3 possible states of the traffic light
enum LightState {
RED("Red", Color.RED), YELLOW("Yellow", Color.YELLOW), GREEN("Green", Color.GREEN);
private LightState(String text, Color color) {
this.text = text;
this.color = color;
}
private String text;
private Color color;
public String getText() {
return text;
}
public Color getColor() {
return color;
}
}

Drawing on top of multiple JButtons

So, I have multiple objects of the class Square, which is the subclass of JButton. I have an instance of the class Board, which contains a few instances of Square. What I want to do is when I press one of the buttons (squares), draw a shape (a circle) on top of it. For doing that, I have a boolean variable in the Square class, namely isClicked, that basically decides what has to be drawn in the paintComponent method.
The problem is that buttons start to behave in a weird way when I have a few of them. Surprisingly, if there is only one of them, there is no problem at all. At first, I had thought the problem might be related to threads, however, I put the main code into invokeLater method and that did not help at all.
I saw a solution using BufferedImage, but I would like to see if there is any possibility to solve the problem doing it my way.
Sorry for possibly not perfect English.
Square class:
public class Square extends JButton implements ActionListener {
private int number;
private boolean isClicked;
public Square(int x) {
number = x;
isClicked = false;
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
if (!isClicked) {
super.paintComponent(g);
} else {
System.out.println("EXECUTED for: " + number);
g2d.drawOval(this.getX(), this.getY(), 100, 100);
}
}
#Override
public void actionPerformed(ActionEvent e) {
isClicked = !isClicked;
System.out.println(isClicked + " " + number);
repaint();
}
}
Board class:
public class Board extends JPanel {
private static final int BOARD_WIDTH = (int) (TicTacToe.WIDTH * 0.7);
private static final int VERTICAL_LINE_LENGTH = (int) (TicTacToe.WIDTH * 0.5);
private static final int HORIZONTAL_LINE_LENGTH = (int) (TicTacToe.HEIGHT * 0.8);
private static final int STROKE_WIDTH = 5;
private Square[] squares;
public Board() {
}
public void addButtons() {
squares = new Square[9];
for (int i = 0; i < 3; i++) {
Square square = new Square(i);
square.setPreferredSize(new Dimension(30, 30));
square.addActionListener(square);
this.add(square);
squares[i] = square;
((GridLayout)this.getLayout()).setHgap(30);
((GridLayout)this.getLayout()).setVgap(30);
}
}
public Square[] getButtons() {
return squares;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(STROKE_WIDTH));
// Horiztontal lines
g2d.drawLine(0, TicTacToe.HEIGHT / 3,
BOARD_WIDTH, TicTacToe.HEIGHT / 3);
g2d.drawLine(0, 2 * TicTacToe.HEIGHT / 3,
BOARD_WIDTH, 2 * TicTacToe.HEIGHT / 3);
// Vertical lines
g2d.drawLine(BOARD_WIDTH / 3, 0, BOARD_WIDTH / 3,
TicTacToe.HEIGHT);
g2d.drawLine(2 * BOARD_WIDTH / 3, 0, 2 * BOARD_WIDTH / 3,
TicTacToe.HEIGHT);
}
}
Main method:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Board board = new Board();
board.setPreferredSize(new Dimension((int) (WIDTH * 0.7), HEIGHT));
board.setLayout(new GridLayout(3, 3));
board.addButtons();
GameOptions opt = new GameOptions();
opt.setPreferredSize(new Dimension((int) (WIDTH * 0.3), HEIGHT));
JFrame frame = new JFrame("Tic Tac Toe");
frame.setLayout(new FlowLayout());
frame.add(board);
frame.add(opt);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
Your use of getX() and getY() on the button's drawing code is completely wrong and does not belong. These methods return the location of the button relative to its container, and so while this might work for a button located at the upper left, it will fail for anything else since you'll end up drawing somewhere far away from the button itself, and so many of your drawings will never show.
You'd be much better off not extending JButton but instead simply swapping ImageIcons that display what you want drawn on the JButton. This is much simpler and much more idiot-proof. You set the button's icon by calling .setIcon(myImageIcon) on it, passing in the icon of choice.
But if you absolutely wanted to draw on the button, you'd do so without using getX() or getY(). You'd also probably want to use a JToggleButton as the parent class, since you're toggling state. For example, my MCVE:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawButtonPanel extends JPanel {
private static final int SIDE = 3;
private static final int GAP = 5;
private static final Color BG = Color.BLACK;
public DrawButtonPanel() {
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new GridLayout(SIDE, SIDE, GAP, GAP));
setBackground(BG);
for (int i = 0; i < SIDE * SIDE; i++) {
// add(new DrawButton1());
DrawButton2 drawButton2 = new DrawButton2(i);
AbstractButton button = drawButton2.getButton();
add(button);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawButtonPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class DrawButton2 {
private static final int PREF_W = 200;
private static final int PREF_H = PREF_W;
private static final int GAP = 20;
private static final float STROKE_WIDTH = 15f;
private static final Stroke BASIC_STROKE = new BasicStroke(STROKE_WIDTH);
private static final Color COLOR = Color.RED;
private static final Color BG = Color.LIGHT_GRAY;
private AbstractButton button = new JToggleButton();
private int index;
public DrawButton2(int index) {
this.index = index;
button.setBorderPainted(false);
button.setBorder(null);
button.setIcon(createPlainIcon());
button.setSelectedIcon(createSelectedIcon());
button.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
System.out.println("Index: " + index);
}
}
});
}
public int getIndex() {
return index;
}
private Icon createPlainIcon() {
BufferedImage img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(new Color(0, 0, 0, 0));
g2d.fillRect(0, 0, PREF_W, PREF_H);
g2d.dispose();
return new ImageIcon(img);
}
private Icon createSelectedIcon() {
BufferedImage img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(BASIC_STROKE);
g2d.setColor(BG);
g2d.fillRect(0, 0, PREF_W, PREF_H);
g2d.setColor(COLOR);
g2d.drawOval(GAP, GAP, PREF_W - 2 * GAP, PREF_H - 2 * GAP);
g2d.dispose();
return new ImageIcon(img);
}
public AbstractButton getButton() {
return button;
}
}
#SuppressWarnings("serial")
class DrawButton1 extends JToggleButton {
private static final int PREF_W = 200;
private static final int PREF_H = PREF_W;
private static final int GAP = 20;
private static final float STROKE_WIDTH = 15f;
private static final Stroke BASIC_STROKE = new BasicStroke(STROKE_WIDTH);
private static final Color COLOR = Color.RED;
private static final Color BG = Color.LIGHT_GRAY;
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(BASIC_STROKE);
if (!isSelected()) {
super.paintComponent(g);
} else {
g2d.setColor(BG);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setColor(COLOR);
g2d.drawOval(GAP, GAP, getWidth() - 2 * GAP, getHeight() - 2 * GAP);
}
g2d.dispose(); // since we created a new one
}
}
Edited to show how to do this with JToggleButton and icons.

How to paint a circle with a random size on a random coordinate such that the circle is fully visible?

Code:
Random rand = new Random();
JPanel mainPanel;
int randomSize = 0;
int randomPositionX = 0;
int randomPositionY = 0;
final static int FRAME_HEIGHT = 500;
final static int FRAME_WIDTH = 500;
final static int TITLE_BAR = 30 ;
final static int MAX_SIZE = 100;
final static int MIN_SIZE = 10 ;
/* All the below code is put into a method */
mainPanel = new JPanel(){
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(randomPositionY, randomPositionX, randomSize, randomSize);
}
};
do{
randomSize = rand.nextInt(MAX_SIZE) + 1;
}while(randomSize < MIN_SIZE);
do{
randomPositionX = rand.nextInt(FRAME_WIDTH);
randomPositionY = rand.nextInt(FRAME_HEIGHT);
}while((randomPositionX + randomSize > FRAME_WIDTH) || (randomPositionY + randomSize > FRAME_HEIGHT - TITLE_BAR));
repaint();
What I want is the circle to have a random size such that it should have a minimum size of 10 and a maximum size of 100. The circle should also be painted in a random coordinate such that the circle is fully visible inside the JPanel mainPanel.
Note that mainPanel will be added to a JFrame whose size is set using setSize(FRAME_WIDTH, FRAME_HEIGHT);.
But the problem is that sometimes, a part of the circle is half outside and half inside the JPanel:
Where did I go wrong?
You're trying to use the frame size when calculating the position of the circle, when the frame includes a variable high title bar AND frame insets
You're trying to use the frame size when it's irrelevant, it's the component's size you should be using, as it's within the mainPanel's coordinate context which you want to paint
So, how do I fix the issues?
Discard ALL the frame "padding"/"offsets". The mainPanel has it's own coordinate context (it's top left corner will be 0x0) and it will be within it's parent's coordinate context, so you don't need to care about the frame or it's insets.
Simplify your calculations, for example...
int randomSize = MIN_SIZE + (rand.nextInt(MAX_SIZE) + 1);
int randomPositionX = rand.nextInt(getWidth() - randomSize);
int randomPositionY = rand.nextInt(getHeight() - randomSize);
Should allow you to produce results which won't fall outside of the viewable area, as the maximum range of the dimensions is the current size of the container minus the desired size, just beware, if the available size is smaller then MAX_SIZE, you will have issues ;)
The example generates a new circle every second
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
public final static int MAX_SIZE = 100;
public final static int MIN_SIZE = 10;
private Rectangle bounds;
private Random rand;
public TestPane() {
rand = new Random();
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int randomSize = MIN_SIZE + (rand.nextInt(MAX_SIZE) + 1);
int randomPositionX = rand.nextInt(getWidth() - randomSize);
int randomPositionY = rand.nextInt(getHeight() - randomSize);
bounds = new Rectangle(randomPositionX, randomPositionY, randomSize, randomSize);
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (bounds != null) {
g2d.setColor(Color.RED);
g2d.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
}
g2d.dispose();
}
}
}

Java Array Loop Graphics page not functioning

edit 2: I decided that it would be easier to understand if I just put the entire code up, so that you can test it.
edit: I realize that what I said was unclear, so I will explain this as best as I can. Basically, I am drawing rectangles on a Graphics page using the fillRect method. The problem is that when I change the size of one, they all change, as they are all being redrawn everytime a new one is drawn. To correct this, I added an array that stores all of the sizes which are input via the scrollwheel in another part of the problem. Anyways, I know that the problem is isolated to the loop that supposedly draws them all a certain size, so I added a loop that in theory should give me a temporary variable each time to use that redraws all of the rectangle's sizes starting at 0 each time the main loop is run. The problem is that this does not in fact redraw the rectangles to their individual sizes, and instead draws them to the current size. I have updated the code part as well.
I am having trouble with a project in Java. What it is supposed to do is change the size of each individual rectangle object by storing it in an array, and then recreating the rectangles based off the length from the array. I (at least I think) do this by creating a variable that should be equal to the SIZE that is changed in another part of the program, and then set that equal to the particular element in the array at i. Anyhow, when I do this, I change all of the lengths to whatever the current length is when I draw a rectangle. I know that the problem is by me using i in the size part, but what would I use? Thanks in advance for any help!
Here is the code:
public class Dots
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Array Rectangles");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DotsPanel dotsPanel = new DotsPanel();
frame.getContentPane().add(dotsPanel);
//buttons
JButton btnNewButton = new JButton("RED");
btnNewButton.setHorizontalAlignment(SwingConstants.LEFT);
btnNewButton.setVerticalAlignment(SwingConstants.BOTTOM);
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
btnNewButton.setForeground(Color.RED);
dotsPanel.add(btnNewButton);
JButton btnNewButton_1 = new JButton("GREEN");
btnNewButton_1.setForeground(Color.GREEN);
btnNewButton_1.setVerticalAlignment(SwingConstants.BOTTOM);
dotsPanel.add(btnNewButton_1);
JButton btnNewButton_2 = new JButton("BLUE");
btnNewButton_2.setForeground(Color.BLUE);
dotsPanel.add(btnNewButton_2);
JButton btnNewButton_3 = new JButton("BLACK");
btnNewButton_3.setForeground(new Color(0, 0, 0));
dotsPanel.add(btnNewButton_3);
frame.pack();
frame.setVisible(true);
}
}
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
public class DotsPanel extends JPanel
{
// radius of each dot
private int SIZE = 25;
private int SIZEAccess;
private static final Random generator = new Random();
//used to count amount of dots
private ArrayList<Point> pointList;
int[] sizes = new int [10000];
//Sets up this std. sized panel to listen for mouse events.
public DotsPanel()
{
pointList = new ArrayList<Point>();
addMouseListener (new DotsListener());
addMouseMotionListener(new DotsListener());
addMouseWheelListener(new DotsListener());
setBackground(Color.white);
setPreferredSize(new Dimension(1024, 768));
}
//used to generate a random color
public static Color randomColor() {
return new Color(generator.nextInt(256), generator.nextInt(256), generator.nextInt(256));
}
// Draws all of the dots stored in the list.
public void paintComponent(Graphics page)
{
super.paintComponent(page);
//draws a centered dot of random color
int i = 0;
for (Point spot : pointList)
{
sizes[i] = SIZE;
//SIZEAccess = SIZE;
//sizes[i] = SIZEAccess;
//page.fillRect(spot.x-SIZE, spot.y-SIZE, SIZE*2, SIZE*2);
for (int temp = 0; temp <= i; temp++)
page.fillRect(spot.x-sizes[temp], spot.y-sizes[temp], sizes[temp]*2, sizes[temp]*2);
//page.fillRect(spot.x-SIZE, spot.y-SIZE, SIZE*2, SIZE*2);
//page.setColor(randomColor());
//page.setColor(c)
i++;
}
//displays the amount of rectangles drawn at the top left of screen
page.drawString("Count: " + pointList.size(), 5, 15);
page.drawString("To change the size of the squares, use mouse scroll wheel.", 350, 15);
page.drawString("Size: " + SIZE, 950, 15);
}
// Represents the listener for mouse events.
private class DotsListener implements MouseListener, MouseMotionListener, MouseWheelListener
{
// Adds the current point to the list of points and redraws
// the panel whenever the mouse button is pressed.
public void mousePressed(MouseEvent event)
{
pointList.add(event.getPoint());
repaint();
}
// Provide empty definitions for unused event methods.
public void mouseClicked(MouseEvent event) {
}
public void mouseReleased(MouseEvent event) {
}
public void mouseEntered(MouseEvent event) {
}
public void mouseExited(MouseEvent event) {}
// Adds the current point to the list of points and redraws
// the panel whenever the mouse button is dragged.
public void mouseDragged(MouseEvent event) {
pointList.add(event.getPoint());
repaint();
}
public void mouseMoved(MouseEvent event) {
}
public void mouseWheelMoved(MouseWheelEvent event)
{
int notches = 0;
notches = event.getWheelRotation();
//int
if (notches > 0)
{
SIZE = SIZE + notches;
notches = 0;
}
else if (notches < 0)
{
int tempSIZE = SIZE;
tempSIZE = tempSIZE + notches;
//prevents the program from having dots that increase due to multiplying negatives by negatives
//by making anything less than 1 equal 1
if(tempSIZE < 1)
tempSIZE = 1;
SIZE = tempSIZE;
notches = 0;
}
}
}
//SIZE = SIZE + notches;
}
You appear to have ArrayList's interacting with arrays in a confusing mix that makes it hard for us to follow your logic. This suggests that your logic may be too complex for your own good and that your code might benefit from simplification. Why not instead create a List<Rectangle> such as an ArrayList<Rectangle>, and then simply loop through this list in your paintComponent method, and draw each Rectangle using the Graphics2D object's draw(...) or fill(...) method:
private List<Rectangle> rectangleList = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle rectangle : rectangleList) {
g2.fill(rectangle);
}
}
For example:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Foo extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final Color BACKGROUND = Color.black;
private static final Color FILL_COLOR = Color.pink;
private static final Color DRAW_COLOR = Color.red;
private static final Stroke STROKE = new BasicStroke(3);
private List<Rectangle> rectangleList = new ArrayList<>();
private Point pressPoint = null;
private Point dragPoint = null;
public Foo() {
setBackground(BACKGROUND);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Stroke oldStroke = g2.getStroke();
g2.setStroke(STROKE);
for (Rectangle rectangle : rectangleList) {
g2.setColor(FILL_COLOR);
g2.fill(rectangle);
g2.setColor(DRAW_COLOR);
g2.draw(rectangle);
}
g2.setStroke(oldStroke);
if (pressPoint != null && dragPoint != null) {
g2.setColor(FILL_COLOR.darker());
int x = Math.min(pressPoint.x, dragPoint.x);
int y = Math.min(pressPoint.y, dragPoint.y);
int width = Math.abs(pressPoint.x - dragPoint.x);
int height = Math.abs(pressPoint.y - dragPoint.y);
g2.drawRect(x, y, width, height);
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
pressPoint = e.getPoint();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
dragPoint = e.getPoint();
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
dragPoint = e.getPoint();
int x = Math.min(pressPoint.x, dragPoint.x);
int y = Math.min(pressPoint.y, dragPoint.y);
int width = Math.abs(pressPoint.x - dragPoint.x);
int height = Math.abs(pressPoint.y - dragPoint.y);
Rectangle rect = new Rectangle(x, y, width, height);
rectangleList.add(rect);
pressPoint = null;
dragPoint = null;
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Foo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Java, Grid of Objects

I need help with drawing the grids to the GUI as well as the program later letting me change the colour of the boxes drawn. I know i will have to use paintComponent(Graphics g), but i have no idea how or where.
So here is a copy of the code i have got so far ( even though i have been told it can be quite daunting just being given code i think it is the best way for people to help and not just do it for me). From the top it sets values, creates the GUI, calls the GUI, fills a 2d array with boxes( i think). Then in the Boxes class setting values the boxes class will need, then the start of how to draw them (didn't know how to work it out), then some seta methods for the x and y coordinates.
what i would like you to do is show how to have the boxes be drawn to the Jpanel, to make a grid and then to show me how to change the colour to different shades of blue, depending on a external value.
import java.awt.*;
import java.awt.Graphics;
import java.util.*;
import javax.swing.*;
public class NewGrid {
Boxes[][] Boxs;
int BoxesX;
int BoxesY;
NewGrid() {
buildtheGUI();
}
JFrame frame = new JFrame();
JPanel panel = new JPanel();
public void buildtheGUI() {
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
new NewGrid();
}
public void addboxes() {
Boxs = new Boxes[panel.getWidth() / 10][panel.getHeight() / 10];
for (int i = 0; i < panel.getWidth() / 10; i++) {
for (int j = 0; j < panel.getHeight() / 10; j++) {
Boxs[i][j] = new Boxes();
Boxs[i][j].setx(i * (panel.getWidth() / 10));
Boxs[i][j].sety(j * (panel.getHeight() / 10));
Boxs[i][j].draw(null);
}
}
}
}
public class Boxes extends JPanel {
int x;
int y;
int width = 10;
int hieight = 10;
Color colour = Color.BLACK;
public void draw(Graphics g) {
g.setColor(colour);
g.fillRect(x, y, width, hieight);
}
public void setx(int i ){
x = i;
}
public void sety(int i ){
y = i;
}
}
I can't comment something, to try to make things easier,
I code there box.putClientProperty(unique_identifier, value_for_identifier), you can to multiple this method as you want
from every Swing Listener you can to get this and proper coordinated defined in putClientProperty
.
JComponent comp = event.getComponent();
String strRow = (String) comp.getClientProperty("row");
String strColumn = (String) comp.getClientProperty("column");
simple code
import java.awt.*;
import java.awt.Graphics;
import java.util.*;
import javax.swing.*;
public class NewGrid {
private int row = 10;
private int column = 10;
private JFrame frame = new JFrame();
private JPanel panel = new JPanel();
private NewGrid() {
addboxes();
panel.setLayout(new GridLayout(row, column));
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private void addboxes() {
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
Boxes box = new Boxes();
box.putClientProperty("row", row);
box.putClientProperty("column", column);
panel.add(box);
}
}
}
public static void main(String[] args) {
Runnable doRun = new Runnable() {
#Override
public void run() {
new NewGrid();
}
};
SwingUtilities.invokeLater(doRun);
}
}
class Boxes extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(20, 20);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(20, 20);
}
#Override
public void paintComponent(Graphics g) {
int margin = 2;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2,
dim.height - margin * 2);
}
}

Categories

Resources