Reputation: 31
private void moveSquare(int x, int y) {
int OFFSET = 1;
if ((squareX!=x) || (squareY!=y)) {
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
squareX=x;
squareY=y;
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
}
}
In the above code (complete code can be found in the Demo App of the "Performing Custom Painting" Java Tutorial), the first repaint
method should paint a square at the position of the previous square, and the second repaint
should paint another square at position of the new square. But this is actually not happening. Instead, the previous square disappears and the new one is painted.
How does the new square get painted while the previous one disappears?
Upvotes: 1
Views: 610
Reputation: 5055
After you call repaint()
it do not repaint the component instantly. But it add the request to paint the component again in the event queue in EDT.
What happens in each code line is expained below..
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
Mark the area bounded by the square (squareX,squareY,squareW+OFFSET,squareH+OFFSET)
is going to be repaint. But it do not get repainted until RepaintManager
do so..
squareX=x;
squareY=y;
Change the value of squareX
and squareY
. But it do not change the earlier marked region to be repainted. Now also, the region to be repainted is previous values.
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
Mark the area bounded by the square (squareX,squareY,squareW+OFFSET,squareH+OFFSET)
is going to be repaint. Now there are two parts that RepaintManager
has to repaint. Previous square and new square. But it do not get repainted until RepaintManager
do so..
Finally when the time comes, RepaintManager
paints the component.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("This is my custom Panel!",10,20);
g.setColor(Color.RED);
g.fillRect(squareX,squareY,squareW,squareH);
g.setColor(Color.BLACK);
g.drawRect(squareX,squareY,squareW,squareH);
}
Now the component is painting only 2 areas. (Previous square and the new square) But the red square will be drawn only within the new square. In the old square there is nothing to draw. So previously drawn things will be erased..
Actually though there are 2 method calls for repaint()
, paintComponents()
will be called only once. The total area to be repainted is handled by RepaintManager
and paintComponents()
is called only once..
Upvotes: 1
Reputation: 3956
The docs you linked to answer your question, at least in general:
although we have invoked
repaint
twice in a row in the same event handler, Swing is smart enough to take that information and repaint those sections of the screen all in one single paint operation.
When you call repaint
, you are not actually painting anything yet, but requesting a repaint at some time in the future.
While the repaint
JavaDoc doesn't go into any detail, it includes a link to "Painting in AWT and Swing", which includes in the "Paint Processing" section two cases, the second of which applies here:
(B) [When the] paint request originates from a call to
repaint()
on an extension ofjavax.swing.JComponent
:
JComponent.repaint()
registers an asynchronous repaint request to the component'sRepaintManager
, which usesinvokeLater()
to queue aRunnable
to later process the request on the event dispatching thread.
And later in that section:
NOTE: if multiple calls to
repaint()
occur on a component or any of its Swing ancestors before the repaint request is processed, those multiple requests may be collapsed into a single call back topaintImmediately()
[...]
By the time your event handler returns, some portion(s) of the JPanel
will have been marked for repainting, possibly all of it. These are called "dirty regions". Swing (eventually) repaints all the dirty regions at once, and only once. This painting happens after your event handler has returned --- meaning after the JPanel
's appearance has been changed --- so the colored square appears in its new location, without any "leftovers" in its old location.
In short, don't think of repaint
as "repaint this area right now", but "add this area to your list of stuff-to-paint-sometime-later".
Upvotes: 1
Reputation: 712
Oracle docs gives good explanation:
moveSquare
method invokes the repaint method not once, but twice. The first invocation tells Swing to repaint the area of the component where the square previously was (the inherited behavior uses the UI Delegate to fill that area with the current background color.) The second invocation paints the area of the component where the square currently is.
Upvotes: 0