views:

4778

answers:

3

Hi all With regards my question (http://stackoverflow.com/questions/772713/call-repaint-from-another-class-in-java). I'm new to java, and I've had a look at some tutorials on SwingWorker, but I'm unsure how to implement it with the example code i gave in the previous question.

Can anyone explain how to use SwingWorker with regards my little bit of code and or point me towards a decent tutorial please? I have looked but I'm not sure I understand yet.

Thanks in advance

Rel

+10  A: 

Generally, SwingWorker is used to perform long-running tasks in Swing.

Running long-running tasks on the Event Dispatch Thread (EDT) can cause the GUI to lock up, so one of the things which were done is to use SwingUtilities.invokeLater and invokeAndWait which performed tasks off the EDT in order to keep the GUI responsive.

However, the problem with the SwingUtilities was that it didn't allow returning data from the other thread back to the original method. This is what SwingWorker was designed to address.

The Java Tutorial has a section on SwingWorker.

Here's an example where a SwingWorker is used to execute a time-consuming task on a separate thread, and displays a message box a second later with the answer.

First off, a class extending SwingWorker will be made:

class AnswerWorker extends SwingWorker<Integer, Integer>
{
 protected Integer doInBackground() throws Exception
 {
  // Do a time-consuming task.
  Thread.sleep(1000);
  return 42;
 }

 protected void done()
 {
  try
  {
   JOptionPane.showMessageDialog(f, get());
  }
  catch (Exception e)
  {
   e.printStackTrace();
  }
 }
}

The return type of the doInBackground and get methods are specified as the first type of the SwingWorker, and the second type is the type used to return for the publish and process methods, which are not used in this example.

Then, in order to invoke the SwingWorker, the execute method is called. In this example, we'll hook an ActionListener to a JButton to execute the AnswerWorker:

JButton b = new JButton("Answer!");
b.addActionListener(new ActionListener() {
 public void actionPerformed(ActionEvent e)
 {
  new AnswerWorker().execute();
 }
});

The above button can be added to a JFrame, and clicked on to get a message box a second later. The following can be used to initialize the GUI for a Swing application:

private void makeGUI()
{
 final JFrame f = new JFrame();
 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 f.getContentPane().setLayout(new FlowLayout());

 // include: "class AnswerWorker" code here.
 // include: "JButton" b code here.

 f.getContentPane().add(b);
 f.getContentPane().add(new JButton("Nothing"));
 f.pack();
 f.setVisible(true);
}

Once the application is run, there will be two buttons. One labeled "Answer!" and another "Nothing". When one clicks on the "Answer!" button, nothing will happen at first, but clicking on the "Nothing" button will work and demonstrate that the GUI is responsive.

And, one second later, the result of the AnswerWorker will appear in the message box.

coobird
I don't believe what I'm doing is a long running task. I have thought of an alternate way to deal with this issue, and will ask in another question. Thanks
Relequestual
A: 

Hey Coobird,

Thanks for your clean explanation. Anyway, I have a question. How does the 'f' variable (JFrame) from the makeGUI() method to the done() method inside de AnswerWorker class?

Alberto
A: 

Alberto,

Look closely at example coobird provided. Within makeGUI() method, there's comment:

// include: "class AnswerWorker" code here.

It states that AnswerWorker is a local inner class of makeGUI() method.

What is means is simple: that class lives w/i scope of makeGUI() method, and has access to final local variables of containing method (see the f declared as final).

Nested classes can be tricky to understand, I particularly found helpful following explanations:

Victor Farazdagi