I'm trying to get the hang of doing graphics stuff (drawing lines,
etc.) in Swing. So far, all the tutorials I've seen declare a class
that overrides paintComponent
, and all the paintComponent
methods
do some set, specific thing, like drawing a red square (although maybe
they draw it at a different location every time). Or maybe they draw a number of lines and shapes, but the paintComponent
method does everything all at once.
I'm trying to figure out: suppose I want to draw one thing in a
component, and later on draw something else on top of it without
erasing what I drew before. My first thought was to have my
paintComponent
override call a callback.
import java.awt.*;
import javax.swing.*;
public class DrawTest {
private interface GraphicsAction {
public void action (Graphics g);
}
private static class TestPanel extends JPanel {
private GraphicsAction paintAction;
public void draw (GraphicsAction action) {
paintAction = action;
repaint();
}
@Override
public void paintComponent (Graphics g) {
super.paintComponent (g);
if (paintAction != null)
paintAction.action(g);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame ("DrawTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(500,500));
TestPanel p = new TestPanel ();
frame.getContentPane().add(p);
frame.pack();
frame.setVisible(true);
p.repaint();
p.draw (new GraphicsAction () {
public void action (Graphics g) {
g.setColor(Color.RED);
g.drawLine(5, 30, 100, 50);
}
});
// in real life, we would do some other stuff and then
// later something would want to add a blue line to the
// diagram
p.draw (new GraphicsAction () {
public void action (Graphics g) {
g.setColor(Color.BLUE);
g.drawLine(5, 30, 150, 40);
}
});
}
public static void main (String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGui();
}
});
}
}
This doesn't work. A blue line shows up, but no red line. I'm
guessing this is because the repaint()
in draw
causes everything
to start over when I draw the blue line, but I'm not sure; anyway, I don't know how else to get
paintComponent
to be called.
Also, if I put a Thread.sleep(1000)
between the two p.draw
calls,
I don't even see the red line for a second. So I'm not at all clear
on how to get my graphics to show up when I want them to.
I've done some searching on "incremental graphics" in Swing, but
nothing that helps find a solution. I found an Oracle article
"Painting in AWT and Swing" that discusses overriding an update()
method to accomplish incremental graphics, but I haven't found any
actual examples of this being done.
So how would I get this to do what I want? It seems like a common
enough task that there should be a simple way to do it, but I haven't
found one. I'm assuming it should be doable without calling
getGraphics
, which, based on other StackOverflow responses would be,
at best, kind of gauche.