Reputation: 9
I'm writing a Java program that will draw a circle or rectangle depending on the button pressed. While it does draw the given shape, upon drawing it creates new buttons at the top left((0,0) most likely) of the window. Am I breaking some rule of paint()/repaint()?
Here's my class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class Components extends JPanel implements ActionListener
{
String em="Nothing";
public Components()
{
JButton c=new JButton("Rectangle");
JButton b=new JButton("Circle");
b.addActionListener(this);
c.addActionListener(this);
add(c, 0);
add(b, 1);
setBackground(Color.WHITE);
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals("Rectangle"))
{
em="Rectangle";
repaint();
}
else
{
em="Circle";
repaint();
}
}
public void paint(Graphics g)
{
if(em.equals("Rectangle"))
{
g.drawRect(50, 50, 50, 50);
}
else if(em.equals("Circle"))
{
g.drawOval(50, 50, 50, 50);
}
}
}
As well as the less-important JFrame class:
import java.awt.Graphics;
import javax.swing.JFrame;
public class Wndw extends JFrame
{
public Wndw()
{
setTitle("Hello");
setSize(400, 400);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(new Components());
}
public static void main (String [] args)
{
new Wndw();
}
}
Upvotes: 0
Views: 378
Reputation: 347332
It's got (very little) to do with repaint
and everything to do with your violation of the painting routines
Start by having a look at Performing Custom Painting and Painting in AWT and Swing for more details into how painting works.
paint
delegates it's responsibilities, by calling paintComponent
, paintBorder
and paintChildren
. When you override paint
and fail to call it's super
method, you are breaking this responsibility and you end up with issues like you have now.
The Graphics
context is a shared resource among Swing components. Every component which is painted during a paint cycle gets the same Graphics
. This means, one of the first things that should be done, is the Graphics
context should be prepared for the component to paint on it. This is typically done by the paintComponent
method, which you are no longer calling
The first thing to do to is, stop overriding paint
and instead, which is generally recommended, override paintComponent
, it limits your overall responsibility and reduces the risk of introducing further issues.
Next, call super.paintComponent
before you do any custom painting...
public class Components extends JPanel implements ActionListener
{
//....
@Overrride
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if(em.equals("Rectangle"))
{
g.drawRect(50, 50, 50, 50);
}
else if(em.equals("Circle"))
{
g.drawOval(50, 50, 50, 50);
}
}
But when I do this, what was previously paint is erased
Yes, that's how painting works. It's destructive. When ever a paint pass is executed, you are expected to repaint the entire state of the component as it is at that point in time.
If you wish to preserve what was previously painted, you have two basic choices.
List
There are plenty of examples of both
Upvotes: 2