Asked  6 Months ago    Answers:  5   Viewed   33 times

Related to my previous question: Call repaint from another class in Java?

I'm new to Java and I've had a look at some tutorials on SwingWorker. Yet, I'm unsure how to implement it with the example code I gave in the previous question.

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

 Answers

41

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 keeps the GUI responsive by which prioritizing the other AWT events before running the desired task (in the form of a Runnable).

However, the problem with SwingUtilities is that it didn't allow returning data from the the executed Runnable 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.

Tuesday, June 1, 2021
 
RenegadeAndy
answered 6 Months ago
69

Just don't go via a Reader - read the data from the InputStream and write to an OutputStream.

// Using Guava (guava-libraries.googlecode.com)
InputStream data = response.getEntity().getContent();
try {
    OutputStream output = new FileOutputStream(filename);
    try {
        ByteStreams.copy(data, output);
    } finally {
        Closeables.closeQuietly(output);
    }
} finally {
}
Thursday, August 5, 2021
 
williamcarswell
answered 4 Months ago
71

If you are using Eclipse RCP, you should use Jobs API. In plain SWT, there is no built-in solution. You need to use Display.asyncExec to update the table.

Friday, September 3, 2021
 
seaders
answered 3 Months ago
62

The SwingWorker's API documentation offers this hint:

The doInBackground() method is called on this thread. This is where all background activities should happen. To notify PropertyChangeListeners about bound properties changes use the firePropertyChange and getPropertyChangeSupport() methods. By default there are two bound properties available: state and progress.

MainWorker can implement PropertyChangeListener. It can then register itself with its PropertyChangeSupport:

getPropertyChangeSupport().addPropertyChangeListener( this );

MainWorker can supply its PropertyChangeSupport object to every MyTask object it creates.

new MyTask( ..., this.getPropertyChangeSupport() );

A MyTask object can then notify its MainWorker of progress or property updates by using PropertyChangeSupport.firePropertyChange methods.

MainWorker, so notified, can then use SwingUtilities.invokeLater or SwingUtilities.invokeAndWait to update the Swing components via the EDT.

protected Void doInBackground() {
    final int TASK_COUNT = 10;
    getPropertyChangeSupport().addPropertyChangeListener(this);
    CountDownLatch latch = new CountDownLatch( TASK_COUNT ); // java.util.concurrent
    Collection<Thread> threads = new HashSet<Thread>();
    for (int i = 0; i < TASK_COUNT; i++) {
        MyTask task = new MyTask( ..., latch, this.getPropertyChangeSupport() ) );
        threads.add( new Thread( task ) );
    }
    for (Thread thread: threads) {
        thread.start();
    }
    latch.await();
    return null;
}
Thursday, September 23, 2021
 
DukeOfMarmalade
answered 2 Months ago
10

This is a two way implementation, meaning that the page you want to call needs to have a callback that listens to such a message and give an appropriate response. You can't simply use it as a swap replacement for AJAX. The best method for that is to use a server-side proxy.

See this page for an explanation of how postMessage works.

Saturday, November 27, 2021
 
N Sharma
answered 3 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share