This should be simple enough, yet I can't make it work.
I have two classes, one which should draw a circle, and the other which sets up a frame and panel with a button. On clicking the button, a circle should appear on the frame. I am confused as to why it doesn't appear. It's probably something very simple, sorry.
package ballsOnPane;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Display implements ActionListener{
private JFrame frame;
private JPanel panel;
private JButton button;
public static void main(String[] args) {
Display display = new Display();
}
public Display() {
frame = new JFrame();
frame.setSize(800, 500);
frame.setTitle("Show balls");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
panel = new JPanel();
frame.add(panel, BorderLayout.CENTER);
button = new JButton("New Ball");
frame.add(button, BorderLayout.SOUTH);
button.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
Ball ball = new Ball(100, 100, 50);
panel.add(ball);
}
}
and ball class:
package ballsOnPane;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
public class Ball extends JPanel{
private int x;
private int y;
private int r;
public Ball(int x, int y, int r){
this.x = x;
this.y = y;
this.r = r;
}
public void paintComponent(Graphics g) {
Graphics2D g2 =(Graphics2D) g;
Ellipse2D circ = new Ellipse2D.Float(x, y, r, r);
g2.draw(circ);
}
}
When you add components to a visible GUI the basic code is:
panel.add(...);
panel.revalidate(); // to invoke the layout manager
panel.repaint(); // to repaint the components
Otherwise the size of the components added is (0, 0) so there is nothing to paint. The same goes for the button. It should be added BEFORE the frame is visible, or you need to do the revalidate()/repaint() as well.
In this case you also have a second problem:
frame.add(panel, BorderLayout.CENTER);
First you add an empty panel to the CENTER of the BorderLayout, then when you click the button you add the Ball to the CENTER.
Swing will paint the last component added first. So the ball gets painted and then the empty panel gets painted over top.
Get rid of the panel, it serves no purpose.
Edit:
For some reason I thought you were adding the Ball to the frame instead of the panel when you clicked the button.
My explanation above was correct if you did in fact add the Ball directly to the frame.
However, my explanation is incorrect since your code in the ActionListener does add the Ball to the panel. The proper explanation is below.
When you add the Ball to the panel, you don't see the Ball because by default a JPanel uses a FlowLayout and the FlowLayout respects the preferred size of any component added to it. You did not implement the getPreferredSize()
method so the size is (0, 0) so there is nothing to paint.
So if you do implement the getPreferredSize()
method in your Ball class the Ball will dislay on the panel. Also, you will be able to display a new Ball every time you click on the button.