(я обновляю свой ответ, чтобы сделать его более понятным и обобщенным)
Несмотря на то, что вы успешно развязали свою логику и представление, это не сделано так, чтобы можно было повторно использовать код. Java PropertyChangeSupport позволяет легко отделить логику от презентации, реализуя связанные свойства и получить существенное повторное использование. Идея состоит в том, чтобы использовать обработчики событий вместо объектов действий.
Во-первых, концептуализировать абстракцию. Фоновая работа должна периодически «выкрикивать» (публиковать) графический интерфейс, и графический интерфейс должен его прослушивать. Два общих класса будут кодифицировать эту идею:
/**
* Wrapper for the background logic.
*
* <T> return type
* <S> intermediary type (the "shout out")
*/
public static abstract class LoudCall<T, S> implements Callable<T> {
private PropertyChangeSupport pcs;
private S shout;
public LoudCall() {
pcs = new PropertyChangeSupport(this);
}
public void shoutOut(S s) {
pcs.firePropertyChange("shoutOut", this.shout,
this.shout = s);
}
public void addListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void removeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
@Override
public abstract T call() throws Exception;
}
/**
* Wrapper for the GUI listener.
*
* <T> return type
* <S> intermediary type (the "shout out" to listen for)
*/
public static abstract class ListenerTask<T, S> extends SwingWorker<T, S>
implements PropertyChangeListener {
private LoudCall<T, S> aMethod;
public ListenerTask(LoudCall<T, S> aMethod) {
this.aMethod = aMethod;
}
@Override
protected T doInBackground() throws Exception {
aMethod.addListener(this);
return aMethod.call();
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("shoutOut".equals(evt.getPropertyName())) {
publish((S)evt.getNewValue());
}
}
@Override
protected abstract void process(List<S> chunks);
}
Эти классы могут использоваться для всех ваших виджетов Swing. Для ProgressBar «кричать» будет Integer, а тип возвращаемого значения - Void:
public class ProgressExample {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// 1. setup the progress bar
final JProgressBar progressBar = new JProgressBar(0, 99);
// 2. Wrap the logic in a "Loud Call"
LoudCall<Void, Integer> aMethod = new LoudCall<Void, Integer>() {
@Override
public Void call() throws Exception {
for (int i = 0; i < 100; i++) {
// "i have an update for the GUI!"
shoutOut(i);
Thread.sleep(100);
}
return null;
}
};
// 3. Run it with a "Listener Task"
(new ListenerTask<Void, Integer>(aMethod) {
@Override
protected void process(List<Integer> chunks) {
progressBar.setValue(chunks.get(chunks.size() - 1));
}
}).execute();
// 4. show it off!
JOptionPane.showOptionDialog(null,
new Object[] { "Process", progressBar }, "Process",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
null, null, null
);
}
});
}
}
Только слушатель должен знать что-либо о деталях GUI, а фоновая логика все еще контролирует публикацию (косвенно, «крича»). Этот код более краткий, читаемый и многократно используемый.
Я понимаю, что этот вопрос довольно старый, но, надеюсь, он кому-нибудь поможет!