Управление GUI и EDT в многозадачном приложении - PullRequest
3 голосов
/ 21 сентября 2011

Я разработал Java-приложение для создания и распаковки архива, например WinRAR . Вы можете создать несколько архивов одновременно с многопоточностью. А недавно я хотел добавлять информацию о статусе при создании архива в виде JProgressBar в новый JFrame при каждом создании.

Но моя проблема - генерировать информацию в новом статусном фрейме и в потоке, который создает архив. Вот почему я создаю JFrame в ветке архива для обновления индикатора выполнения в настоящее время.

Но, как я мог бы прочитать в разнообразном источнике информации и в ваших ответах / комментариях, это противоречит Java Swing и производительности; Я не могу создать объект свинга в другом месте, где EDT .

Но тогда как мне решить мою проблему? Как я могу установить связь между записью моего архива и его статусом JFrame (с JProgressBar)?


EDIT:

Я реализовал SwingWorker для управления GUI в моем приложении. Теперь все готово, у меня есть другой вопрос:

С SwingWorker, как мне действовать в фоновом режиме с событием на кнопке состояния кадра? (Пример: приостановить сжатие или остановить его.)

Ответы [ 3 ]

5 голосов
/ 21 сентября 2011

Как подсказывают другие, лучший способ - использовать SwingWorker.

SwingWorker свойства доступны для прослушивания, и слушатели всегда вызываются в EDT, таким образом, вы можете сделать что-то вроде:

public class ArchivingWorker extends SwingWorker<Void, Void> {
    JProgressBar progressBar = null;
    // Other members here...
    ...

    public ArchivingWorker(...) {
        // Any specific initialization here (in EDT)
        addPropertyChangeListener(new PropertyChangeListener() {
            @Override void propertyChange(PropertyChangeEvent e) {
                if (    "state".equals(e.getPropertyName())
                    &&  e.getNewValue() == StateValue.STARTED) {
                    // Background thread has just started, show a progress dialog here
                    progressBar = new JProgressBar();
                    ...
                }
                else if ("progress".equals(e.getPropertyName())) {
                    // Update progress bar here with e.getNewValue()
                    ...
                }
            }
        });
    }

    @Override protected Void doInBackground() {
        // Archiving process here and update progress from time to time
        setProgress(progress);

        return null;
    }

    @Override protected void done() {
        // Ensure that archiving process worked correctly (no exception)
        try {
            get();
        } catch (Exception e) {
            // Handle exception (user feedback or whatever)
        } finally {
            // Close progress dialog
            ...
        }
    }
}

Тогда вы можете использовать ArchivingWorker по мере необходимости:

ArchivngWorker worker = new ArchivingWorker(...);
worker.execute();
5 голосов
/ 21 сентября 2011
  1. Поместите и отобразите JProgressBar в JDialog и не создавайте новый Контейнер верхнего уровня . Создайте это один раз и снова используйте это

  2. Долгосрочный и тяжелый код лучше перенаправить на задание BackGround

  3. Вы можете перейти с прогрессом в JProgressBar из фонового задания

    • только если код, связанный с графическим интерфейсом, выполняется на EDT далее Параллелизм в Swing

    • и есть два правильных способа сделать это

      • с помощью SwingWorker

      • из Runnable#Thread, но связанный с GUI код должен быть заключен в invokeLater()

1 голос
/ 21 сентября 2011

Ответ, предоставленный @ mKorbel , в порядке, но на самом деле нет необходимости использовать другой контейнер верхнего уровня (например, JDialog) для отображения индикатора выполнения.Вместо этого вы можете использовать Glass Pane экземпляра JFrame.

...