Been Googling for a few days and I can't figure out how to tell if paintComponent is being called while I'm processing paintComponent. The process is long and complicated. If I have a second (or third) request to paint, I want to abort the current paint process and start over with the most recent request.
-
3*"..paintComponent. The process is long and complicated."* That is the problem that needs to be fixed. No 'long running task' should be done in, or called from, the paint methods. – Andrew Thompson Sep 16 '16 at 15:06
-
1@AndrewThompson "No 'long running task' should be done in, or called from, the paint methods." You are literally stating that Java is incapable of handling long-running visual algorithms. I think you meant to state that long-running visual algorithms should be launched as a separate thread to close the paint method quickly. Try to be more informative and less snarky. – kainaw Sep 16 '16 at 16:19
2 Answers
You can't; calls to paintComponent()
are queued, blocking the EDT until completed. Use the approach shown in this AnimationTest
to self-time your implementation on a typical target platform. Optimize as required. As a concrete example, this KineticModel
illustrates several animation techniques that may apply to your use case.
Addendum: Your update suggests that the "long and complicated" process involves constructing a BufferedImage
for later display. To avoid blocking the EDT, do this in the background of a SwingWorker
from which you can publish()
interim results as they become available. This example simulates building a raster image one line at a time.
This related example constructs a TexturePaint
in a similar manner.
For specific guidance, edit your question to include a Minimal, Complete, and Verifiable example that shows your revised approach.
As usual, I think of a solution after asking for one... My solution is to launch a thread that progressively updates a BufferedImage. Then, the paintComponent method is just two lines:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(myImage, 0, 0, null);
}
The image is drawn very quickly. Calling super is required to erase the existing view of the image before redrawing it.
The rest of the solution is creating a thread that updates the myImage attribute of the panel. In my work, the image takes about 30 minutes to process completely, depending on the input to the program. It isn't a big deal unless I drag the window or accidentally touch the mouse wheel while the application is running. Then, paintComponent is called again and hangs the program. With this solution, the update can take days and you can resize or move the window all you want. You keep seeing the image as it has been processed so far.

- 4,256
- 1
- 18
- 38
-
You can fix your mouse wheel bump problem by having two buffered images. The paintComponent method draws myOldImage. myOldImage isn't updated until myImage is finished rendering. I'm curious as to why your image takes 30 minutes or so to render. Perhaps you could do the calculations first, then do the drawing on myImage. – Gilbert Le Blanc Sep 16 '16 at 19:51
-
I'm not sure this is an answer to the question. It will certainly lead to the kind of problems you've encountered. Please edit your question to reflect your use case. I've updated my answer to cite two relevant examples. – trashgod Sep 16 '16 at 22:38