Моя "проблема" может быть описана следующим. Предположите, что у нас есть интенсивный процесс, что мы хотим иметь выполнение в фоновом режиме и иметь его, обновляют панель JProgress Swing. Решение легко:
import java.util.List;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
/**
* @author Savvas Dalkitsis
*/
public class Test {
public static void main(String[] args) {
final JProgressBar progressBar = new JProgressBar(0,99);
SwingWorker<Void, Integer> w = new SwingWorker<Void, Integer>(){
@Override
protected void process(List<Integer> chunks) {
progressBar.setValue(chunks.get(chunks.size()-1));
}
@Override
protected Void doInBackground() throws Exception {
for (int i=0;i<100;i++) {
publish(i);
Thread.sleep(300);
}
return null;
}
};
w.execute();
JOptionPane.showOptionDialog(null,
new Object[] { "Process", progressBar }, "Process",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
null, null, null);
}
}
Теперь предположите, что у меня есть различные методы, которые занимают много времени. Например, у нас есть метод, который загружает файл с сервера. Или другой, который загружает на сервер. Или что-либо действительно. Каков надлежащий способ делегировать опубликовать метод к тем методам так, чтобы они могли обновить GUI соответственно?
Что я нашел, до сих пор это (предположите, что метод "aMethod" находится в некотором другом пакете, например):
import java.awt.event.ActionEvent;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
/**
* @author Savvas Dalkitsis
*/
public class Test {
public static void main(String[] args) {
final JProgressBar progressBar = new JProgressBar(0,99);
SwingWorker<Void, Integer> w = new SwingWorker<Void, Integer>(){
@Override
protected void process(List<Integer> chunks) {
progressBar.setValue(chunks.get(chunks.size()-1));
}
@SuppressWarnings("serial")
@Override
protected Void doInBackground() throws Exception {
aMethod(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
publish((Integer)getValue("progress"));
}
});
return null;
}
};
w.execute();
JOptionPane.showOptionDialog(null,
new Object[] { "Process", progressBar }, "Process",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE,
null, null, null);
}
public static void aMethod (Action action) {
for (int i=0;i<100;i++) {
action.putValue("progress", i);
action.actionPerformed(null);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Это работает, но я знаю, что это испытывает недостаток в чем-то. Какие-либо мысли?
Я столкнулся с аналогичной проблемой. Вот что я обнаружил, возможно, действительно правильного ответа нет, но давайте попробуем:
doInBackGround ()
. JProgressBar - это параметр конструктора нашего SwingWorker, который расширяет SwingWorker (так что да, мы используем custom) В третьем пункте я описал, как выполнить поток из метода, который выполняет некоторую задачу, которая не является итеративной (по крайней мере, в нашем Java-коде) и не может быть прервана. Поток обновляет JProgressBar, который был задан как параметр метода. Это, однако, определенно медленнее как чистый вызов метода
Возможно, сделать SwingWorker для каждого длинного метода. Каждый SwingWorker имеет свой собственный уровень прогресса.
Каждый SwingWorker обновляет свой собственный уровень прогресса во время метода doInBackground, затем вызывает publish. Внутри метода process, то есть внутри EDT, каждый SwingWorker считывает свой уровень прогресса, обновляет модель и общий индикатор прогресса.