开发者

Java - SwingWorker - Can we call one SwingWorker from other SwingWorker instead of EDT

I have a SwingWorker as follows:

public class MainWorker extends SwingWorker(Void, MyObject) {
    :
    :
}

I invoked the above Swing 开发者_如何学JAVAWorker from EDT:

MainWorker mainWorker = new MainWorker();
mainWorker.execute();

Now, the mainWorker creates 10 instances of a MyTask class so that each instance will run on its own thread so as to complete the work faster.

But the problem is I want to update the gui from time to time while the tasks are running. I know that if the task was executed by the mainWorker itself, I could have used publish() and process() methods to update the gui.

But as the tasks are executed by threads different from the Swingworker thread, how can I update the gui from intermediate results generated by threads executing tasks.


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;
}


Even if you do not use SwingWorker, you can always post things to do in the EDT using SwingUtilities.invokeLater(...) or SwingUtilities.invokeAndWait(...)

EDIT: suppose that you have a thread executing some code, you can always interact with EDT like in the example below.

public void aMethodExecutedInAThread() {

    // Do some computation, calculation in a separated Thread

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            // Post information in the EDT
            // This code is executed inside EDT
        }
    });
}


Here is an example that uses a SwingWorker to launch multiple threads. A CountDownLatch ensures that doInBackground() returns only when all threads have completed. Each thread uses the thread-safe append() method of JTextArea to update the GUI, but EventQueue.invokeLater() would be a convenient alternative.


Read these artcles to get a clear picture of your problem

Threads and Swing

Using a Swing Worker Thread

The last word in Swing Threads

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜