This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
Here's a quick snippet of code. "ap" is the old AbstractAnimatedPanel.
For all intents and purposes, AbstractAnimatedPanel extends Canvas, and the MainFrame class (which has this method) is a JFrame. I know, I know...mixing AWT and Swing. No lecture needed, unless it's relevant to this question. This is simply part of a program that is a mental exercise for myself.
The problem here is that, between remove(ap), and add(ap), the content pane is redrawn, creating a flicker when switching panels. While ap is added to the frame, I do not have a flicker; that's not an issue. The ap variable actively renders.
With this in mind, how can I possibly tell the content pane to stop repainting entirely during this window of time? I've tried overriding the paint(Graphics g) method, the update(Graphics g) method, the repaint(long time, int x, int y, int width, int height) method, the paintComponents(Graphics g) method, and setIgnoreRepaint(true) on both the frame and the content pane. Additionally, I've tried replacing the contentPane with a JPanel and calling setOpaque(false). While many of these techniques are not recommended (such as the last one), I'm just putting it out there to say that I've tried it. I'm quite stumped.
Oh, and I should mention that I have also tried adding the new animated panel before the synchronized block. Flicker still appears.
The official way is to call getGlassPane().setVisible(true) on the JFrame. Under these conditions, the UI thinks that it's covered up, so it doesn't repaint. When you want painting to start again, setVisible(false).
I tinkered around a bit more and came up with a solution that was close to working last night. But, something didn't seem right...it flickered once on the third flip, and then was fine from thereon out.
I investigated a bit more closely this evening, and it appears that the remove(ap) call was not truly removing the item from the array of components retrieved via this.getComponents(). My solution involved placing the content pane at the maximum z-ordering, and layering the other two over one another appropriately. No wonder the flicker never happened after the third flip...the z-ordering was 30-ish after 30 flips. I'm not quite sure what would have happened if I had let that be, but I'm guessing that there's a limit that results in a nasty stack trace eventually, since the array cleaned up nicely when working with lightweight components inside of the JFrame.
So, I went to an AWT Frame. Voila, everything worked perfectly. No more flicker with the new strategy. Here's the final solution for the method:
For the readers out there, this method essentially adds the new incoming actively-rendering Canvas (animPanel) to the Frame, calls validate (necessary after manipulating layout on a visible container), and then, grabs a lock and waits for the buffer strategy to have something to look at. Once it does, then it covers the old canvas with the new by setting z ordering. Validation occurs again, and the old panel is told to stop animating. Once done (with animation and with cleaning up its threads for loading images, rendering, etc, it's always good to clean up after oneself), the old panel is removed from the frame. Finally, the newAnimPanel takes the place of the old, validation is called once again, and we're done.
Now, are there easier ways to do things? You bet. There might be something better than what I did. But in all reality, you should probably use something like swing. Or do web or mobile programming, which is where the money is most of the time (I'm not biased, it's just my day job ).
Thanks for the assistance. Onward to figuring out how to make the AWT frame actually do stuff.