Что такое потокобезопасное использование (отправление событий) для JOptionPane.showMessageDialog и swing.utils.invokeAndWait?

У меня есть простой groovy script, который из основного потока выполнения должен отображать пользователю некоторые диалоговые окна.

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

Если я просто вызову статический метод JOptionPane.showMessageDialog из своего основного потока, правильно ли я предполагаю, что это нарушит правильную практику хранения материалов с графическим интерфейсом в EDT?

Должен ли я на самом деле использовать метод swing.utils.invokeAndWait, как в следующем примере кода?


void showHelloThereDialog() 
        throws Exception {
    Runnable showModalDialog = new 
      Runnable() {
        public void run() {
            JOptionPane.showMessageDialog(
               myMainFrame, "Hello There");
        }
    };
    SwingUtilities.invokeAndWait
       (showModalDialog);
}

Теперь вышеприведенное не делает ничего, чтобы сделать значения из чего-то другого, кроме диалогового окна сообщения, доступными после завершения invokeAndWait.

Предположительно тот факт, что заводные «замыкания» реализуют Runnable, сделает код более простым, чем указано выше.

Требуется invokeAndWait? И если да, то не мог бы кто-нибудь привести пример правильной реализации, чтобы получить результат чего-то вроде подтверждения диалога с использованием groovy?


person Alex Stoddard    schedule 30.03.2011    source источник
comment
Если вы пишете код Swing и используете Groovy, вам следует проверить Griffon.   -  person Dónal    schedule 31.03.2011
comment
@Don Спасибо за предложение, я знаю о гриффоне, и это определенно интересно. С другой стороны, это намного тяжелее, чем то, что мне нужно прямо сейчас, и я также чувствую, что хочу немного лучше понять гайки и болты, прежде чем полагаться на столько магии. Единственная документация, о которой я знаю, это MEAP Griffon в действии manning.com/almiray. Знаете ли вы, хорошо ли это (или полезны ли другие источники)?   -  person Alex Stoddard    schedule 31.03.2011


Ответы (3)


Взгляните на groovy.swing.SwingBuilder, он инкапсулирует функции invokeAndWait и invokeLater. Ваш пример можно записать так:

import groovy.swing.SwingBuilder
import javax.swing.*
import java.awt.*

def swing = new SwingBuilder()
def myMainFrame = new Frame()

swing.edt {
    JOptionPane.showMessageDialog(
        myMainFrame, "Hello There");
}
person Christoph Walesch    schedule 30.03.2011

Вызов одного из методов showXXXDialog() JOptionPane БЛОКИРУЕТСЯ до тех пор, пока пользователь не выберет ok/cancel/etc. Как правило, вы не размещаете такие медленные блокирующие инструкции в потоке отправки событий (EDT), потому что каждый другой компонент графического интерфейса будет зависать. Итак, интуиция не ставить его на EDT — это хорошо, но также и неправильно. Причина в том, что, как утверждают некоторые другие, метод создает компоненты графического интерфейса, и это всегда следует делать в EDT. Но как быть с блокировкой? Вы заметите, что даже если вы запустите его на EDT, он работает нормально. Причина находится внутри исходного кода. Класс JOptionPane создает объект Dialog, а затем вызывает show(), за которым следует dispose(), первый из которых блокирует поток. Если вы прочитаете комментарии (или javadoc), вы увидите, что там говорится о методе:

Если диалоговое окно модальное и еще не видимое, этот вызов не вернется, пока диалоговое окно не будет скрыто вызовом hide или dispose. Допустимо показывать модальные диалоги из потока диспетчеризации событий, потому что инструментарий гарантирует, что другой насос событий будет запущен, в то время как тот, который вызвал этот метод, заблокирован.

Таким образом, запуск JOptionPane в EDT совершенно безопасен, несмотря на его блокировку. Очевидно, безопасно вызывать метод Dialog show() вне EDT, но то же самое нельзя сказать о JOptionPane, потому что его методы создают компоненты графического интерфейса, добавляют прослушиватели, получают доступ к другим контейнерам в модальном режиме и блокируют ввод в них и т. д. Вы не хотите, чтобы все это делается вне EDT, потому что он не является потокобезопасным и могут возникнуть проблемы. По общему признанию, я никогда не видел проблем при использовании JOptionPane без EDT, поэтому шансы кажутся низкими, но они, безусловно, возможны. Передача нулевого значения для контейнера диалога и предоставление только неизменяемых объектов (например, Strings) в качестве аргументов для полей значительно уменьшит (возможно, даже устранит, насколько мне известно) вероятность чего-то плохого, потому что все соответствующие компоненты графического интерфейса сделаны и доступны в том же потоке, пока они не видны. Но вы должны быть в безопасности и поставить его на EDT. Позвонить SwingUtilities.invokeAndWait() не так уж и сложно.

person David    schedule 21.07.2012

Это должно быть в EDT, поэтому требуются invokeAndWait или invokeLater. Вы можете сказать, так как код для JOptionPane.showMessageDialog в конечном итоге создает и изменяет компоненты Swing. Что касается Java 6, Sun говорит, что все манипуляции с компонентами Swing (независимо от того, реализованы они или нет) должны выполняться в EDT.

http://download.oracle.com/javase/6/docs/api/javax/swing/package-summary.html

http://www.velocityreviews.com/forums/t707173-why-does-jdk-1-6-recommend-creating-swing-components-on-the-edt.html

person Matt Crinklaw-Vogt    schedule 30.03.2011