Управление графическим интерфейсом и EDT в многозадачном приложении

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

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

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

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


ИЗМЕНИТЬ:

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

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


person damson    schedule 21.09.2011    source источник


Ответы (3)


Как предлагали другие, лучший способ - использовать 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();
person jfpoilpret    schedule 21.09.2011
comment
Я действительно забыл спросить вас, знаете ли вы что-нибудь о stackoverflow.com/questions/7053865/ - person mKorbel; 22.09.2011
comment
@mKorbel Нет, но я буду учиться. Я полагаю, это говорит о поведении рабочего-свингера. - person damson; 22.09.2011
comment
@jfpoilpret Я согласен, но в вашем методе doInBackground есть проблема, потому что JprogressBar не будет обновляться в EDT. В остальном спасибо за остальное, что дает мне немного облака для концепции. Но я буду работать с swingWorker, потому что PropertyChangeListener пока несколько размыт. - person damson; 22.09.2011
comment
@damson Я не думаю, что индикатор выполнения не будет обновляться в EDT. SwingWorker.setProgress() вызывает PropertyChangeEvent, для которого все зарегистрированные слушатели будут вызваны в EDT, поэтому я поместил фактическое обновление индикатора выполнения в PropertyChangeListener. Если вы не уверены, просто распечатайте SwingUtilities.isEventDispatchThread() из PCL. - person jfpoilpret; 22.09.2011
comment
хорошо, я не видел, что это был метод SwingWorker. Это просто идеально для моего случая. Благодарность - person damson; 22.09.2011
comment
Спасибо, мне удалось интегрировать SwingWorker и этот roxx, но теперь у меня другая проблема. Как действовать в фоновой задаче с событием кнопки статуса Frame? Я сделал это, когда управлял другой задачей вручную, но теперь с swingWorker это действительно особенно. У вас есть идея концепции, чтобы сделать это? - person damson; 23.09.2011
comment
@jfpoilpret Я говорю слишком быстро. Когда я запускаю свое приложение на старом компьютере, у них есть некоторая задержка в графическом интерфейсе. Так же, как когда я запускал свое приложение без swingWorker в аналогичных условиях. что ты думаешь об этом ? - person damson; 23.09.2011
comment
@Damson Я думаю, было бы предпочтительнее, если бы вы начали новый вопрос и опубликовали код, который вы написали до сих пор. Трудно сказать, что может быть не так с таким небольшим описанием. - person jfpoilpret; 24.09.2011

  1. Поместите и отобразите JProgressBar в JDialog и не создавайте новый файл Контейнер верхнего уровня. Создайте это один раз и используйте повторно

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

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

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

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

      • с помощью SwingWorker

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

person mKorbel    schedule 21.09.2011
comment
Я думаю, что понял параллелизм в производительности свинга. И я начал разрабатывать новую реализацию с помощью SwingUtilities (invokeLater / isEventDispatchThread), но код слишком тяжелый, а в графическом интерфейсе состояния есть ошибка и зависание. Я попробую со SwingWorker. - person damson; 21.09.2011
comment
да, верно, проверьте мои сообщения, отмеченные тегом Table и SwingWorker, тогда вы можете выбрать лучший и самый простой вариант ... - person mKorbel; 21.09.2011
comment
в порядке. Знаешь что ? Я внедрим SwingWorker в свое приложение, и если у меня возникнут проблемы, я вернусь, чтобы проверить вас. - person damson; 21.09.2011
comment
снова Runnable # Thread проще для ошибок новичка или если что-то пошло не так, - person mKorbel; 21.09.2011
comment
@mKorbel: +1 молодец! И не забудьте пригласить меня в карьеры stackoverflow, если вы получите доступ;) - person Heisenbug; 21.09.2011
comment
Да, я знаю, что у меня нет проблем с Runnable#Thread. Моя проблема связана с производительностью свинга - person damson; 21.09.2011
comment
@damson нет никаких различий между этими двумя методами относительно / с производительностью, кстати, это не проблема Java (ваша тема), потому что три или более winrar работают одновременно, чтобы убить процессоры SATA + в ОС Win 32b. - person mKorbel; 21.09.2011
comment
@Heisenbug понятия не имею, что .., можешь дать мне ссылку на свои сокровища :-) - person mKorbel; 21.09.2011

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

person mrkhrts    schedule 21.09.2011
comment
Спасибо за ответы. Что касается контейнера верхнего уровня, у меня нет выбора, чтобы использовать его, потому что JDialog берет на себя все внимание приложения, и многозадачность становится бесполезной. (Я не знаю, понятно ли я; скажи мне, если я не понимаю) - person damson; 21.09.2011
comment
@damson, нет... в этом не было особого смысла. - person mrkhrts; 21.09.2011