I'm considering porting our internal automotive/measuring application from Swing to JavaFX, mainly because of the better look and multitouch support, but I can't find a way to render custom components only when they are visible.
For motivation, imagine a screen with 10 tabs, and inside each tab is a plot displaying some live data being measured. At any time, only one plot can be seen. The amount of data is large, the computer has enough power to render one plot at a time, but not all of them simultaneously.
Swing version
Now in the Swing version, the implementation of this behavior was straightforward. Each plot is a custom JComponent with overriden paintComponent method that does all the plot drawing. paintComponent gets called in two important cases:
- When the component becomes visible, e.g. user selects the tab with the plot
- When the live data change, my code calls a repaint() on the component, that in turn results in paintComponent being called if that component is visible (or when it becomes visible again).
It is more complicated than this (see http://www.oracle.com/technetwork/java/painting-140037.html for details), but it works roughly like this. The important thing is that only the plots that are visible are also being processed and redrawn..
Porting to JavaFX?
Now I'm trying to port this behaviour to JavaFX, the natural choice being Canvas. But the paintComponent callback mechanism is gone, you just draw directly into the Canvas.getGraphicsContext2D.
If I understand correctly, calling draw operations on this context doesn't really perform any immediate drawing, it just pushes the operations on a stack that gets processed later by the Prism subsystem when the Prism thread runs (is this correct?). So, probably (I'm just guessing, I'm pretty new to JavaFX), there would be no actual painting at all if Prism discovers that the Canvas is not visible (another tab is selected, it is obscured by another Node, lies outside the visible portion of Screen, ...), is this correct? That would be nice.
But even if this is this case, it doesn't help me, because I don't want to even start the rendering until I know that the Canvas is visible. Even preprocessing the live data for plotting can take quite a lot of CPU power, perhaps even more than the rendering itself - imagine interpolating thousands of data points to plot just a few lines. So, after the live data changes, I'd like to first test the actual visibility of each plot (Canvas) before starting its redraw. I also need to be notified when it becomes visible. Is this somehow possible with JavaFX? Or am I taking a bad route altogether with Canvas and there is a better way?
P.S. Please, don't confuse this visibility with Node.visibleProperty, that one does something different, basically switches off the Node from rendering.