2010-02-18 3 views
5

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

Я попытался сделать класс SwingWorker внешним, который отлично подходит для процесса, к сожалению, я не могу получить доступ к каким-либо моим полям GUI из класса SwingWorker. Всякий раз, когда я пытаюсь получить доступ к атрибуту, например меток или тому подобное из метода done() SwingWorker, я получаю исключение 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. :) Еще раз большое спасибо за вашу помощь!

ответ

6

Вы можете сделать 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 конструктору свинг работника, вы бы метод установки и тогда было бы что-то вроде:

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

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

+0

Также можно было бы просто передать ярлык в конструкторе, а не в runnable. Однако определение нового рабочего подкласса для каждого небольшого действия, вероятно, будет чрезмерным. Анонимные классы отлично подходят для решения этой конкретной задачи: собрать очень маленький, тесно связанный объект. –

+0

Это действительно зависит, если это единственный случай использования. Абстракция работает, если вы делаете это во многих местах. О, как бы закрытие было бы полезно. –