Как делегировать SwingWorker, публикуют к другим методам

Моя "проблема" может быть описана следующим. Предположите, что у нас есть интенсивный процесс, что мы хотим иметь выполнение в фоновом режиме и иметь его, обновляют панель 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();
            }
        }
    }

}

Это работает, но я знаю, что это испытывает недостаток в чем-то. Какие-либо мысли?

5
задан Savvas Dalkitsis 25 May 2010 в 20:32
поделиться

2 ответа

Я столкнулся с аналогичной проблемой. Вот что я обнаружил, возможно, действительно правильного ответа нет, но давайте попробуем:

  • если у нас много итераций, мы можем обновить индикатор выполнения в методе doInBackGround () . JProgressBar - это параметр конструктора нашего SwingWorker, который расширяет SwingWorker (так что да, мы используем custom)
  • , если у нас нет итераций, и мы не можем прервать метод, который требует много времени для завершения, мы можем либо все испортить, либо сделать это, как и большинство людей (так что наш индикатор выполнения не имеет линейного процесса, а просто обновляет его значения после выполнения частичной работы). Плохая новость в том, что если наш метод является единственным, который выполняет работник (например, отправляет электронную почту в фоновом режиме), индикатор выполнения станет внезапно заполненным . Хотя не очень хорошо, давайте рассмотрим третий вариант
  • , это может быть довольно сумасшедшим и снижаться производительность, все потому, что наше приложение должно быть модным . Итак, перейдем к исходному коду метода, который требует много времени для завершения.Мы переопределяем его и вставляем точно такой же код, но добавляем еще один параметр - угадайте, да, JProgressBar. Внутри метода мы создаем поток, который будет работать до тех пор, пока некоторый логический параметр (метод, указывающий на флаг не будет окончательно завершен) не будет установлен в значение true. Thread будет продолжать обновлять JProgressBar через некоторые разумные интервалы. Самая большая проблема - предположить, каков разумный интервал. Мы должны пройти несколько тестов и оценить значение интервалов.

В третьем пункте я описал, как выполнить поток из метода, который выполняет некоторую задачу, которая не является итеративной (по крайней мере, в нашем Java-коде) и не может быть прервана. Поток обновляет JProgressBar, который был задан как параметр метода. Это, однако, определенно медленнее как чистый вызов метода

0
ответ дан 13 December 2019 в 22:02
поделиться

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

Каждый SwingWorker обновляет свой собственный уровень прогресса во время метода doInBackground, затем вызывает publish. Внутри метода process, то есть внутри EDT, каждый SwingWorker считывает свой уровень прогресса, обновляет модель и общий индикатор прогресса.

0
ответ дан 13 December 2019 в 22:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: