pete stein wrote:I've never seen a background thread called from within the paintComponent method before, and while I suppose that there may be rare times when this may be done (but I haven't a clue as to one) I don't feel that this is one of them. Why not create the BufferedImage in a background thread not called by paintComponent, and then when done, call repaint() on the drawing JPanel, and in the paintComponent method if the BufferedImage isn't null, paint it by calling g.drawImage(myBufferedImage,.....)?
Oh, by the way, thanks for the link to the cross-post; it's much appreciated.
From the code posted above, JFreeChart does render the chart to a BufferedImage first and then paints the buffered image to the canvas / JPanel. I think they do this because it allows for better abstraction among the renders, but if only one chart is rendered, it would slow things down a bit compared to directly rendering to the screen. One question I have though is how would multiple repaint events be handled? For example, when I resize a window, the Swing Event Dispatcher is actually firing off several repaint events, I'm guessing one per every pixel of frame size change. And if I did this with background thread, how I avoid spawning off one new event per pixel change? Maybe I'm not understanding or forgot some details about how swing works, but it seems that there needs to be some sort of filter for cutting out redundant repaint calls. Second, changes to the chart data set or other chart parameter (zooming, mouse cursor, etc) cause a call to paintComponent where a Graphics object is passed in. So if I were to also call repaint() when the rendering of the BufferedImage is finished, how would I tell whether the call to paintComponent means: 1) something changed, redraw the bufferedImage or 2) buffered image rendering done, paint bufferedImage? In case 1) once the BufferedImage is rendered, another call to paintComponent is made so we would enter an infinite loop. I don't have much experience with Swing Threading, but I think your idea is correct. I just don't see how to implement it.
Update: I was able to implement your approach because JFreeChart has a refreshbuffer flag which indicates whether the bufferedImage needs to be recomputed. So I simply made another function called refreshBuffer where I do just that if the buffer needs rendering. I do the rendering in a separate thread. There's a few problems. First although it draws the charts, there's some glitch at the beginning where all charts are the same for a second or two. Second, I still seem stuck using only one thread. CPU pegs at 25% (on a 4 core machine). I put in some getCurrentSystemTime and I see that each thread takes much longer to execute. So it seems like the threads are running in parallel, but only on one CPU core. I think some of these problems might relate to what I mentioned above in my previous post. If a chart receives multiple update calls, it will simply spawn a new thread for each call. Instead, what should happen is that if there's a more recent update call while the bufferedimage is being rendered, that rendering should stop (be interrupted) and start-over. This is because something has changed since the rendering started and therefore, rendering must be restarted. I suspect that Swing event handler has a way of dealing with this situation. In order to background render, I think there's something else that I'm still missing. Here's the code, all I really did was create a new function refreshBuffer which copies the bufferedImage rendering part of JFreeChart's original paintComponent method.