Отображение GlassPane перед входом в цикл

(В моем приложении с графическим интерфейсом Swing) я хочу отображать GlassPane во время некоторой работы, выполняемой в цикле или методе, который вызывается после нажатия JButton.

Например: (действие выполняется после нажатия кнопки)

if (item.equals(button)) {

    glassPane.setVisible(true);

    someTimeConsumingMethod();

    glassPane.setVisible(false);

}

Выполнение этого кода приводит к тому, что glassPane не отображается во время выполнения someTimeConsumingMethod () - графический интерфейс просто зависает на мгновение, прежде чем отобразится результат. Удаление последней строки в этом цикле (glassPane.setVisible (false);) приводит к отображению glassPane после выполнения метода (когда графический интерфейс размораживается).

Есть ли простой способ показать, что glassPane до того, как GUI зависнет, или мне нужно использовать здесь некоторые дополнительные знания? (потоки?)

ОБНОВЛЕНИЕ1:

Я обновил свой код в соответствии с ответом davidXYZ (с двумя изменениями):

(действие выполняется после нажатия кнопки)

if (item.equals(button)) {

    glassPane.setVisible(true);

        new Thread(new Runnable(){
            public void run(){
                someTimeConsumingMethod(); // 1st change: running the someTimeConsumingMethod in new Thread
                                           //             instead of setting glassPane to visible
            }
        }).start();

    // 2nd change: moved glassPane.setVisible(false); inside the someTimeConsumingMethod(); (placed at the end of it).

}

Точка 1-го изменения заключается в том, что установка glassPane, видимая в новом потоке прямо перед запуском someTimeConsumingMethod в моем потоке графического интерфейса, открывала glassPane после завершения someTimeConsumingMethod (дважды проверил это).

Теперь все работает нормально, спасибо за все ответы. Я обязательно проверю все ссылки, которые вы предоставили, чтобы понять темы!

UPDATE2: Дополнительная информация: someTimeConsumingMethod (); в моем приложении готовятся новые компоненты Swing в соответствии с данными XML (карты, созданные из JButtons и JLabels с несколькими JPanels, где это необходимо, и добавление их в нужных местах).

UPDATE3: Я пытаюсь заставить его работать, используя метод SwingWorker invokeLater. Теперь это выглядит так:

(действие выполняется после нажатия кнопки)

if (item.equals(button)) {

    glassPane.setVisible(true);

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() { 
            someTimeConsumingMethod();
            glassPane.setVisible(false);
        }
    });

}

Работает не так хорошо, как код из UPDATE1 (но все же - работает). Проблемы:

  • glassPane загружается без анимации .gif (файл настраивается в пользовательском классе glassPane - он работает с кодом UPDATE1)

  • есть небольшая задержка в конце «рабочего» процесса - сначала курсор становится нормальным (из WAIT_CURSOR), а через очень короткий момент glassPane исчезает. Курсор изменяется пользовательским классом glassPane при активации / деактивации (без задержки с использованием нового способа Thread).

Это правильный способ использования метода SwingWorker invokeLater?

РЕДАКТИРОВАТЬ: Моя ошибка, я перепутал SwingWorker с SwingUtilities.invokeLater (). Я предполагаю, что проблема с изображением связана с зависанием графического интерфейса при запуске someTimeCOnsumingMethod.


person Community    schedule 26.09.2012    source источник
comment
Нужно уточнить. Вы хотите, чтобы glassPane был виден во время работы someTimeConsumingMethod, а затем закрывал его сразу после завершения функции?   -  person davidXYZ    schedule 26.09.2012
comment
Да, именно этого я и хочу добиться. До сих пор я думал, что выполнение кадра упорядочено сверху вниз (глядя на код в каком-то редакторе) - когда заканчивается одна инструкция, начинается следующая, но я думаю, это не так просто. Постараюсь решить мою проблему предоставленными ответами.   -  person TV.    schedule 26.09.2012
comment
В этом случае вам определенно понадобится другой поток для обработки некоторых задач. Я дал ответ ниже с примером.   -  person davidXYZ    schedule 26.09.2012


Ответы (4)


GUI просто зависает на мгновение, прежде чем отобразится результат. Удаление последней строки в этом цикле (glassPane.setVisible (false);) приводит к отображению glassPane после выполнения метода (когда графический интерфейс размораживается).

это обычная проблема для Event Dispath Thread, когда все события в EDT сбрасываются в Swing GUI за один момент, тогда все в методе if (item.equals(button)) { может быть выполнено в один момент,

но в вашем описании говорится, что у вас проблема с Concurency в Swing, часть кода блокирует EDT, это небольшая задержка, например Thread.sleep(int), может вызвать эту проблему, не делайте этого или перенаправляйте блок кода на Backgroung taks

Есть ли простой способ показать это glassPane до того, как GUI зависнет, или мне нужно использовать здесь некоторые дополнительные знания? (потоки?)

этот вопрос - пример бронирования, почему там SwingWorker, или более простой способ - Runnable#Thread

  • методы, реализованные в SwingWorker, вполне гарантируют, что вывод будет выполнен на EDT

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

самые простые шаги из Jbuttons Action могут быть

  • показать GlassPane

  • запустить фоновую задачу с SwingWorker (убедитесь, что PropertyChangeListener прослушивает) или вызовите Runnable#Thread

  • в этот момент ActionListener выполнений выполнено, остальной код перенаправлен на Backgroung taks

  • если задача завершилась, то скрыть GlassPane

  • создать простую пустоту, обернув setVisible в invokeLater() для Runnable#Thread

  • в случае, если вы используете SwingWorker, вы можете скрыть GlassPane при соответствующем событии от PropertyChangeListener или вы можете использовать любую (отдельную) пустоту для сокрытия GlassPane

лучший код для GlassPane от @camickr или моего вопрос на основе этого кода

person mKorbel    schedule 26.09.2012
comment
Спасибо за очень подробный ответ, я кое-что почитал ;-). - person TV.; 26.09.2012
comment
как уже упоминалось, @Guillaume Polet и я тоже перемещаем выполнение кода, например. someTimeConsumingMethod(); в SwingWorker или Runnable#Thread - person mKorbel; 27.09.2012
comment
Вы можете видеть в UPDATE3, что someTimeConsumingMethod (); прямо сейчас работает из SwingWorker, который работает с небольшими проблемами, описанными в примере. Я не знаю, правильно ли я использую метод SwingWorker invokeLater. - person TV.; 27.09.2012
comment
вы можете использовать этот код для имитации любых проблем с GlassPane, есть четыре разных метода - person mKorbel; 27.09.2012
comment
@TV Вы путаете SwingWorker и SwingUtilities.invokeLater. Это очень разные вещи, но оба связаны с Swing-thread. Подумайте об использовании SwingWorker, а не SwingUtilities.invokeLater, как я описал в своем ответе. - person Guillaume Polet; 27.09.2012

Вы блокируете EDT (поток диспетчеризации событий, единственный поток, в котором обрабатываются все события пользовательского интерфейса) своим трудоемким заданием.

2 решения:

  1. Оберните вызовы в: someTimeConsumingMethod();glassPane.setVisible(false); в SwingUtilities.invokeLater(), это позволит кадру снова перерисоваться. Однако это все равно остановит ваш графический интерфейс.

  2. Переместите свой someTimeConsumingMethod() в SwingWorker (это рекомендуемый вариант). Это предотвратит зависание вашего графического интерфейса.

Прочтите javadoc SwingWorker, чтобы лучше понять, что происходит и как это использовать. Вы также можете многое узнать из этого руководства по Swing и многопоточности

person Guillaume Polet    schedule 26.09.2012
comment
нет причин, по которым спасибо, ни я, я говорю об описании :-) - person mKorbel; 26.09.2012
comment
@ТЕЛЕВИДЕНИЕ. затем постарайтесь избегать использования того способа, который вы приняли, все, что касается Swing JComponents (в вашем случае GlassPane), должно быть сделано в EDT или завернуто в invokeLater, а жесткий и длительный код должен быть перенаправлен в runnable # thread, я могу показать у вас 1Mio кодов, где требуется блокировать EDT, но работает только в этой форме, приходится выполнять вычисления с большими проблемами, а также в случае многопоточности, вызванной заблокированным текущим экземпляром JVM, пока он не будет убит с помощью диспетчера задач - person mKorbel; 27.09.2012
comment
Спасибо за предупреждение. Я принял ответ, может быть, слишком рано. Я оставлю его открытым еще некоторое время и постараюсь изучить все предоставленные материалы. Пожалуйста, проверьте UPDATE2 для получения новой информации о моем методе, требующем больших затрат времени. - person TV.; 27.09.2012

 JButton startB = new JButton("Start the big operation!");
    startB.addActionListener(new ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent A) {
        // manually control the 1.2/1.3 bug work-around
        glass.setNeedToRedispatch(false);
        glass.setVisible(true);
        startTimer();
      }
    });

Здесь используется стекло FixedGlassPane;

ссылка: http://www.java2s.com/Code/Java/Swing-JFC/Showhowaglasspanecanbeusedtoblockmouseandkeyevents.htm

person Alvin Pradeep    schedule 26.09.2012
comment
это правильный способ отложить желаемое событие из EDT, +1 для Swing Timer - person mKorbel; 26.09.2012

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

Простой способ решить вашу проблему - отключить отображение стеклянной панели в другом потоке (обычный поток или потоки Swing - оба будут работать нормально).

if (item.equals(button)) {
    new Thread(new Runnable(){
        public void run(){
            glassPane.setVisible(true);
        }
    }).start();
    someTimeConsumingMethod();
    glassPane.setVisible(false);
}

Таким образом, другой поток блокируется setvisible(true), а someTimeConsumingMethod() выполняется в основном потоке. Когда это будет сделано, стекло исчезнет. Анонимный поток достигает конца run метода и останавливается.

person davidXYZ    schedule 26.09.2012
comment
Я использовал ваш пример в своем коде, проверьте мой обновленный вопрос, если интересно. - person TV.; 26.09.2012
comment
Хорошо, давайте нарушим оболочку EDT ... Было бы лучше использовать SwingWorker и отключить стеклянную панель в методе done ... - person MadProgrammer; 27.09.2012
comment
-1. Это действительно плохой совет. UI-манипуляции должны выполняться на EDT. @MadProgrammer прав. - person Guillaume Polet; 27.09.2012
comment
Если это не так, то это плохой совет? - person davidXYZ; 27.09.2012
comment
@davidXYZ Вы все еще блокируете EDT с помощью someTimeConsumingMethod. Попробуйте изменить размер окна во время работы метода, он не будет работать должным образом, потому что запросы на перерисовку больше не обрабатываются из-за того, что someTimeConsumingMethod теперь блокирует очередь событий - person MadProgrammer; 27.09.2012
comment
@MadProgrammer: в моем приложении весь фрейм на мгновение заблокирован, когда загружаются данные XML (это когда отображается Glass Pane - блокировка ввода и предоставление информации о том, что приложение считывает данные). Размер рамки нельзя изменить. В таком случае это все еще плохой способ? - person TV.; 27.09.2012
comment
@MadProgrammer На самом деле я не пробовал изменять размер окна. Если то, что вы говорите, правда, я приму это к сведению. Я просто знал, что отображение должно быть в ветке различий, а не в методе. Во всяком случае, посмотрите обновление вопроса. TV оставил UI в основном потоке, а метод - в побочном. Это работает. Спасибо за информацию. - person davidXYZ; 27.09.2012
comment
@davidXYZ Ваше предположение Я просто знал, что отображение должно быть в потоке сравнения, чем метод. правильный. Но кроме того, все, что связано с пользовательским интерфейсом, должно выполняться в EDT, потому что такие вещи, как RepaintEvent, InputEvent и т. Д., Отправляются в этом потоке. В конце концов, это означает, что все, что требует много времени, должно быть убрано с EDT. Чтобы узнать, как это сделать, ознакомьтесь с другими ответами. - person Guillaume Polet; 27.09.2012
comment
Когда вы открываете любую программу и начинаете загружать данные, вы обычно хотите изменить размер окна? Зачем???? Интересно, зачем кому-то жаловаться на это. Телевизор, я не думаю, что есть проблема, если вы не прикасаетесь к кадру во время загрузки данных. Можете ли вы всегда перетаскивать MSWord, Eclipse, веб-браузер или любое другое программное обеспечение во время загрузки данных ?? Иногда забавно то, к чему придираются люди. - person davidXYZ; 27.09.2012
comment
Пожалуйста, проверьте UPDATE2 для получения новой информации о моем методе, требующем больших затрат времени. - person TV.; 27.09.2012
comment
davidXYZ, пока я доволен вашим ответом, и я не думаю, что вы не правы, потому что он работает, но это может быть из-за недостатка (моих) знаний. - person TV.; 27.09.2012
comment
@GuillaumePolet Я узнал об этом сегодня. Я не знал, что всегда лучше оставлять UI на EDT. Спасибо - person davidXYZ; 27.09.2012
comment
@davidXYZ проблема с вашим примером заключается в том, что someTimeConsumingMethod и glassPane.setVisible(false); должны выполняться ДО запуска вашего потока обновления (для вызова glassPane.setVisible(true), что вообще нежелательно. Другая проблема, с которой вы сталкиваетесь, - это грязные обновления, когда одна часть экран обновляется не синхронно с остальными. Вы часто видите это, когда люди используют сортировщики строк таблицы и пытаются добавить / удалить модель таблицы вне EDT. - person MadProgrammer; 27.09.2012
comment
@davidXYZ Когда вы открываете любую программу и начинаете загружать данные, вы обычно хотите изменить размер окна? - это непочтительно, ваш код заставит программу выглядеть так, как будто она зависла, и пользователь будет соблазнен принудительно прекратить его. ИМХО выглядит непрофессионально и убого. Я согласен, вы должны сообщать пользователю, что вы выполняете длительную задачу, но не определяя удобство использования программы. Первое правило Swing - обновления пользовательского интерфейса (любой части пользовательского интерфейса) должны выполняться на EDT, второе правило - блокировать EDT. - person MadProgrammer; 27.09.2012
comment
@MadProgrammer Что касается последней части вашего комментария, я думаю, вы имели в виду НЕ блокировать EDT - person Guillaume Polet; 27.09.2012
comment
@GuillaumePolet Доброе утро: P Да, ты прав, я скоро поболтаю с моими толстыми пальцами - person MadProgrammer; 27.09.2012