4

I'm writing a simple Java Swing application that is designed as a demo for a course. The purpose of the program is to visualize the progress of a recursive method (specifically, a recursive solution to a maze). I'd like to be able to update the appearance of the JComponent as the recursive method executes, so from the perspective of Swing the updates can't be triggered individually from a Timer class, which I gather is the usual method for animations.

My first thought was just to call repaint() whenever I want to redraw the visualization. But the recursive method itself is called in the event handler of a JButton, which means all the calls to repaint() are delayed until the event handler terminates -- and all I get to see is the last frame of the animation. I found that I can get the drawing to happen immediately if I call update() instead, like this:

getRootPane().getContentPane().update(getGraphics());
try {
    Thread.sleep(25);
} catch (Exception e) {
}

This almost works, except that the animation flickers. I know that Swing is double-buffered, but apparently getGraphics gives me the active buffer rather than the back buffer. I can't see any methods that would give me access to the back buffer.

So I'm looking for a solution that would allow me to repaint the component in the middle of the recursion and give me a flicker-free animation. Is there a way to activate the built-in double-buffering while an event handler is executing? Would it be better to try to implement my own buffering system? Or is what I'm trying to do just not possible/advisable with Swing?

(As a final note, this is my first post here. I've tried to write a good question, but if I'm missing anything please let me know nicely and I'll try to do better next time. Thanks!)

mKorbel
  • 109,525
  • 20
  • 134
  • 319
nhowe
  • 909
  • 6
  • 14
  • I think you've included everything :) although it may be helpful to see the recursion to try to pinpoint a spot where a repaint() might be squeezed in. You may end up with some conditionals in the recursion and/or repaint so that it is only called when it is appropriate. – CodeGuy Apr 02 '13 at 22:11
  • Why not maintain a reference to the previous buffer and update with that? – Redandwhite Apr 02 '13 at 23:32

2 Answers2

2

First off, you should not be executing long-running actions in the Event Dispatch Thread, and I assume that's one reason your animation flickers.

So I'd suggest starting off a thread that executes your recursive method when pressing the button (and maybe deactivate it until the work is done).

To render the animation, you may either call myComponent.repaint() from within your recursive method or you start a Swing Timer (Thanks to @mKorbel for poiting that out) which basically looks like this:

ActionListener repaintTrigger = new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
          myComponent.repaint();
      }
};
new Timer(25, repaintTrigger).start();

I recommend the latter approach, as your recursive method should probably not know anything about a Swing component (unless you decouple it via a "ProgressListener" or something).

As it seems your no mere beginner, I just gave some hints on what to do. If you need more input, feel free to ask.

skirsch
  • 1,640
  • 12
  • 24
  • Thanks; that gave me enough to go on. Key insight was that running the recursion on another thread would allow repaint() to be used normally. I like your other suggestions too, although I'm trying to keep the rest of the code simple so that the recursion remains the focus. – nhowe Apr 03 '13 at 00:42
  • not, never (sure could be works), but to use Swing Timer for todays Java6/7 instead – mKorbel Apr 03 '13 at 05:52
  • @mKorbel Haven't been doing much Swing those last years, thanks for pointing me to [`javax.swing.Timer`](http://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html) – skirsch Apr 03 '13 at 06:51
0

I don't actually know if this works but. I would try to make it multi-threaded and separate the recursion from the graphics. I don't know if this works on java but it did work for me in C#.

Daan Luttik
  • 2,781
  • 2
  • 24
  • 37