Responsive GUI in Swing Using Multithreading


Valentino Vranić - Object-Oriented Programming

1. Executing a time-consuming calculation from GUI - GUI blocks, JLabel is not being updated

NastyComputation.java:

public class NastyComputation {
   private MyWindow w;

   public void setWindow(MyWindow w) {
      this.w = w;
   }
   public void compute() {
      w.setBusy();     
      for (int i = 0; i < Integer.MAX_VALUE; i++)
         System.out.println("c");
      w.setFree();
   }
}


MyWindow.java:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MyWindow extends JFrame {
   private NastyComputation c;
   private JButton PressButton = new JButton("Press");
   private JButton CompButton = new JButton("Comp");
   private JLabel l = new JLabel("Free");
   public JPanel p = new JPanel();
   public MyWindow(NastyComputation c) {
      super("MyWindow");
      this.c = c;
      setSize(200, 75);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setLayout(new FlowLayout());
      add(PressButton);
      add(CompButton);
      add(l);
      PressButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            if (PressButton.getText() != "Press") {
               PressButton.setText("Press");
            }
            else {
               PressButton.setText("Again");
            }
         }
      });
      CompButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            MyWindow.this.c.compute();
         }
      });
   } // MyWindow(NastyComputation c)

   public void setBusy() {
      l.setText("Busy");
   }
   public void setFree() {
      l.setText("Free");
   }

   public static void main(String[] args) {
      NastyComputation c = new NastyComputation();
      MyWindow w = new MyWindow(c);
      c.setWindow(w);
      w.setVisible(true);
   }
} // MyWindow




2. Executing a time-consuming calculation in its own thread

NastyComputation.java:

import javax.swing.*;

public class NastyComputation {
   private MyWindow w;

   public void setWindow(MyWindow w) {
      this.w = w;
   }
   public void compute() {
      w.setBusy();     
      new Thread() {
         public void run() {
            for (int i = 0; i < Integer.MAX_VALUE; i++)
               System.out.println("c");
            SwingUtilities.invokeLater(new Runnable() {
               public void run() {
                  w.setFree();
               }
            });
         }
      }.start();
   }
}

The MyWindow class (MyWindow.java) remains with no changes




3. Using the SwingWorker class

NastyComputation.java:

public class NastyComputation {
   public void compute() {
      for (int i = 0; i < Integer.MAX_VALUE; i++)
         System.out.println("c");
   }
}

In the MyWindow class (MyWindow.java), the CompButton listener has to be substituted with this code:

      CompButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            setBusy();
            new SwingWorker() {
               public Object doInBackground() {
                  c.compute();
                  return null;
               }
               protected void done() {
                  setFree();
               }
            }.execute();
         }
      });

This call:

   c.setWindow(w);

has to be removed from the main() method.


Valentino Vranić
vranic at stuba.sk