Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does SwingWorker has to be a nested class?

I'm wondering if SwingWorker has to be a nested class within my main GUI. I'd rather make it an external class to keep the GUI clear from any of my programs logic.

I tried to make the SwingWorker class external, which works fine for the process, unfortunately I can't access any of my GUI fields from the SwingWorker class. Whenever I try to access an attribute, such like a label or whatever from within SwingWorker's done() method I get a nullPointer exception.

Any advice would be much appreciated!


First of all thank you very much Jeff! Works fine so far, even though I could not follow you on the second option you presented. One of my background tasks calculates a certain size (long value), so it would be nice to get that value from my GUI.

You suggested to work with getters and setters but unfortunately I've got no idea on how to implement them in the SwingWorker class.

I tried it like this:

public void setSize(long totalSize) {
     this.totalSize = totalSize;
}
public long getTotalSize() {
     return totalSize;
}

The setter is invoked at the end of the doInBackground() method. Unfortunately I can't use the get() method from my GUI.

final MySwingWorker w = new MySwingWorker();
Runnable r = new Runnable() {
    public void run() {
        // do something with w.get()
    }
};
w.setRunnable(r);
w.execute();

The object creation of "w" does not work in my case as the constructor requires an object of Runnable. Am I missing something? Please go easy on me, it's the first time I work with SwingWorker. :) Again, thank you very much for your help!

like image 762
Peter Avatar asked Feb 18 '10 12:02

Peter


People also ask

How does SwingWorker work?

SwingWorker is designed for situations where you need to have a long running task run in a background thread and provide updates to the UI either when done, or while processing. Subclasses of SwingWorker must implement the doInBackground() method to perform the background computation.

Is SwingWorker thread safe?

Since Swing is not thread-safe by design, it's designer did provide couple of utility methods in SwingUtilities class to update any Swing component from a thread other thread Event Dispatcher Thread. You can use invokeAndWait() and invokeLater() to update a Swing component from any arbitrary thread.


1 Answers

You can make the SwingWorker an external class. However, just like any other class, if it can't see the variables (e.g. the label you want to set), of course it won't be able to set it. One thing you could do is pass the worker a Runnable that it executes when it is complete.

public class MySwingWorker extends SwingWorker {

   private final Runnable r;
   public MySwingWorker(Runnable r) {
       this.r = r;
   }
   public void doInBackground() {...}
   public void done() { r.run(); }
 }

Now from the GUI, you might do something like

Runnable updateLabel = new Runnable() {
       public void run() {
           label.setText("myValue");
       }
};
SwingWorker w = new MySwingWorker(updateLabel);
w.execute();

This gets a bit trickier if you want to use the result of the SwingWorker, though it is possible. Rather than passing the Runnable to the swing worker's constructor, you would have a setter method and then it would be something like:

final MySwingWorker w = new MySwingWorker();
Runnable r = new Runnable() {
    public void run() {
        // do something with w.get()
    }
};
w.setRunnable(r);
w.execute();

In either case, the Runnable is functioning similarly to a closure that is executed when the worker is finished.

like image 193
Jeff Storey Avatar answered Sep 24 '22 03:09

Jeff Storey