Должен ли SwingWorker быть вложенным классом? - PullRequest
5 голосов
/ 18 февраля 2010

Мне интересно, должен ли SwingWorker быть вложенным классом в моем основном графическом интерфейсе. Я бы предпочел сделать его внешним классом, чтобы очистить графический интерфейс от логики любой из моих программ.

Я попытался сделать класс SwingWorker внешним, который отлично работает для этого процесса, к сожалению, я не могу получить доступ ни к одному из моих полей GUI из класса SwingWorker. Всякий раз, когда я пытаюсь получить доступ к атрибуту, такому как метка или что-либо еще из done() метода SwingWorker's, я получаю исключение nullPointer.

Любой совет будет высоко ценится!


Прежде всего, большое спасибо, Джефф! До сих пор работает нормально, хотя я не мог следовать за вами по второму варианту, который вы представили. Одна из моих фоновых задач вычисляет определенный размер (длинное значение), поэтому было бы неплохо получить это значение из моего графического интерфейса.

Вы предложили работать с геттерами и сеттерами, но, к сожалению, я понятия не имею, как реализовать их в классе SwingWorker.

Я попробовал это так:

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

Сеттер вызывается в конце метода doInBackground(). К сожалению, я не могу использовать метод get() из моего графического интерфейса.

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

Создание объекта "w" в моем случае не работает, так как для конструктора требуется объект Runnable. Я что-то пропустил? Пожалуйста, будьте спокойны со мной, это первый раз, когда я работаю с SwingWorker. :) Еще раз большое спасибо за помощь!

1 Ответ

6 голосов
/ 18 февраля 2010

Вы можете сделать SwingWorker внешним классом. Однако, как и любой другой класс, если он не может видеть переменные (например, метку, которую вы хотите установить), он, конечно, не сможет ее установить. Единственное, что вы можете сделать, это передать работнику Runnable, который он выполнит по завершении.

public class MySwingWorker extends SwingWorker {

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

Теперь из графического интерфейса вы можете сделать что-то вроде

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

Это немного сложнее, если вы хотите использовать результат SwingWorker, хотя это возможно. Вместо того, чтобы передавать Runnable в конструктор Swing Worker, у вас будет метод setter, и тогда это будет что-то вроде:

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

В любом случае, Runnable функционирует аналогично закрытию, которое выполняется после завершения рабочего процесса.

...