views:

124

answers:

2

I am writing a genetic algorithm that approximates an image with a polygon. While going through the different generations, I'd like to output the progress to a JFrame. However, it seems like the JFrame waits until the GA's while loop finishes to display something. I don't believe it's a problem like repainting, since it eventually does display everything once the while loop exits. I want to GUI to update dynamically even when the while loop is running.

Here is my code:

while (some conditions) {
    //do some other stuff
    gui.displayPolygon(best);
    gui.displayFitness(fitness);
    gui.setVisible(true);
}

public void displayPolygon(Polygon poly) {
    BufferedImage bpoly = ImageProcessor.createImageFromPoly(poly);
    ImageProcessor.displayImage(bpoly, polyPanel);
    this.setVisible(true);
}

public static void displayImage(BufferedImage bimg, JPanel panel) {
    panel.removeAll();
    panel.setBounds(0, 0, bimg.getWidth(), bimg.getHeight());
    JImagePanel innerPanel = new JImagePanel(bimg, 25, 25);
    panel.add(innerPanel);
    innerPanel.setLocation(25, 25);
    innerPanel.setVisible(true);
    panel.setVisible(true);
}
+1  A: 

I think your problem is that Java won't let you update the GUI from another thread than the GUI thread itself. This causes grief to everybody at some point, but fortunately a reasonably convenient workaround is provided.

The idea is to pass the code that does the updating as a Runnable to the method SwingUtilities.invokeAndWait or SwingUtilities.invokeLater. Here's an example.

To run your GA at maximum speed and exploit parallelism, I guess invokeLater would be appropriate.


EDIT: Oh wait, camickr's solution hints that you're doing something else: You're running the GA in the GUI's thread. Well, that can only do one or the other, calculate or display. So the true solution would combine both changes:

  1. Run the GA in a separate thread (you could run it in the thread used by main() after you've instantiated the GUI); and
  2. Use invokeLater to communicate updates to the GUI thread (which camickr calls the EDT, or Event Dispatch Thread).
Carl Smotricz
camickr
That was news to me, thanks! I'd seen SwingWorker before but never gave it much attention.
Carl Smotricz
SwingWorker is the right answer... Thanks!
pypmannetjies
+3  A: 

However, it seems like the JFrame waits until the GA's while loop finishes to display something. I don't believe it's a problem like repainting

Yes, if the looping code execute on the EDT then the GUI can't repaint itself until the loop finishes. The looping code should execute in its own Thread so it doesn't block the EDT.

Read the section from the Swing tutorial on Concurrency for more information.

camickr
+1 to you for your help. Thanks!
Carl Smotricz