I have a code like that:
// In MyPanel.java
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// Draw something
mypanel_count++;
}
// In Test.java
public void testLargeData()
{
while (notDone)
{
panel.repaint();
// do huge work
test_count++;
System.out.println("Test_count: " + test_count + ", MyPanel_count: " + mypanel_count);
}
}
// Output !!!
Test_count: 752, MyPanel_count: 23
Test_count: 753, MyPanel_count: 23
Test_count: 754, MyPanel_count: 23
Test_count: 755, MyPanel_count: 24
But when I change panel.repaint()
to panel.paintComponent(panel.getGraphics())
, the out is right:
Test_count: 752, MyPanel_count: 752 Test_count: 753, MyPanel_count: 753 Test_count: 754, MyPanel_count: 754 Test_count: 755, MyPanel_count: 755
Why? paintComponent
method works, but sometimes it's blind, so I don't want to use it. Anybody can give me some suggestions? Thanks!
The repaint method is an asynchronous method of applet class. When call to repaint method is made, it performs a request to erase and perform redraw of the component after a small delay in time.
The paint() method contains instructions for painting the specific component. The repaint() method, which can't be overridden, is more specific: it controls the update() to paint() process. You should call this method if you want a component to repaint itself or to change its look (but not the size).
repaint(): This method cannot be overridden. It controls the update() -> paint() cycle. We can call this method to get a component to repaint itself. If we have done anything to change the look of the component but not the size then we can call this method.
The repaint () method causes the AWT runtime system to execute the update () method of the Component class which clears the window with the background color of the applet and then calls the paint () method.
If you read the documentation of repaint
carefully, you will notice that it states that (emphasis mine):
If this component is a lightweight component, this method causes a call to this component's paint method as soon as possible. Otherwise, this method causes a call to this component's update method as soon as possible.
This means that AWT/Swing is allowed to optimize repainting by merging repaints that are requested in a rapid succession. There is also a repaint(long time)
method, which allows you to control how long AWT/Swing is allowed to wait with fullfilling your repaint request. It might still merge requests though, especially if you do them in a loop.
It might be helpful to read the article "Painting in AWT and Swing", which tries to explain the various concepts involved.
To get the panel repainted for every iteration, you would have to wait for a paint to happen and then proceed with your loop. This means you need some synchronization between your processing thread (the loop) and the AWT/Swing thread. As a rough idea, you could for example wait()
on the panel object at the end of your loop if it has not been repainted since the last call to repaint()
and call notifyAll()
at the end of your panel's paintComponent()
method. However, this can be tricky to implement right, so you should only do this if you really need "real-time" redrawing of your component. As an alternative, paintImmediately(...)
could be used, but you would have to do all your processing in the event dispatching thread, like this:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
while(notDone) {
// Do your processing
panel.paintImmediately(...);
}
}
});
Note that this will stop any event processing including mouse and keyboard input from being processed while your loop is running. You can read more about Swing and Threading in "Concurrency in Swing"
As the other answers say: it's a problem of when AWT is calling paint()
.
If you do some work that needs information from painted/layouted Components, what helps is also to put this work into a worker thread that waits until the painting is done.
In your case that would be something like:
panel.repaint();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// do huge work
test_count++;
System.out.println("Test_count: " + test_count
+ ", MyPanel_count: " + mypanel_count);
}
});
Although I'm not sure how it would behave in your while
loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With