Поток отправки событий

Поток диспетчеризации событий (EDT) — это фоновый поток, используемый в Java для обработки событий из очереди событий графического пользовательского интерфейса Abstract Window Toolkit (AWT) . Это пример общей концепции программирования, управляемого событиями , которая популярна во многих других контекстах, помимо Java, например, в веб-браузерах или веб-серверах .

События в основном являются событиями обновления, которые заставляют компоненты пользовательского интерфейса перерисовывать себя, или событиями ввода с устройств ввода, таких как мышь или клавиатура. AWT использует однопоточную модель рисования , в которой все обновления экрана должны выполняться из одного потока. Поток диспетчеризации событий является единственным допустимым потоком для обновления визуального состояния видимых компонентов пользовательского интерфейса. Обновление видимых компонентов из других потоков является источником многих распространенных ошибок в программах Java , использующих Swing . [1] Поток диспетчеризации событий называется primordial worker в Adobe Flash и UI-потоком в SWT , .NET Framework и Android .

Цикл сообщений для сериализации доступа к графическому интерфейсу

Программное приложение обычно состоит из нескольких потоков и одной структуры данных GIT. Это означает, что GIT является общей структурой данных, и необходима некоторая синхронизация, чтобы гарантировать, что только один поток получает к ней доступ в каждый момент времени. Хотя AWT и Swing предоставляют методы ( небезопасные для потоков ) для создания и доступа к компонентам GUI, и эти методы видны всем потокам приложения, аналогично в других фреймворках GUI, только один поток Event Dispatching имеет право выполнять эти методы. [2] [3] [4] Поскольку программисты часто упускают это требование, сторонние Look and Feels , такие как Substance, заходят так далеко, что отказываются создавать экземпляры любого компонента Swing, когда он не запущен в потоке Event Dispatch, [5] , чтобы предотвратить такую ​​ошибку кодирования. Доступ к GUI сериализован, и другие потоки могут отправлять некоторый код для выполнения в EDT через очередь сообщений EDT .

То есть, как и в других фреймворках GUI, поток диспетчеризации событий проводит свою жизнь, перекачивая сообщения: он поддерживает очередь сообщений действий, которые должны быть выполнены через GUI. Эти запросы отправляются в очередь системой и любым потоком приложения. EDT потребляет их один за другим и отвечает обновлением компонентов GUI. Сообщения могут быть известными действиями или включать обратные вызовы, ссылки на пользовательские методы, которые должны быть выполнены с помощью EDT.

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

Отправка кода пользователя в EDT

Существуют различные решения для отправки кода в EDT и выполнения длительных задач без блокировки цикла.

Обработчики событий компонентов (прослушиватели)

Компоненты GUI поддерживают списки обратных вызовов, называемых прослушивателями, которые обычно заполняются при создании компонентов. EDT запускает прослушиватели, когда пользователь каким-либо образом возбуждает компоненты (нажатие кнопки, перемещение мыши, выбор элемента, потеря фокуса, изменение размера компонента и т. д.).

Таймер

Для коротких задач, которые должны периодически или в определенное время получать доступ к GUI/изменять его, javax.swing.Timerиспользуется. Его можно рассматривать как невидимый компонент GUI, слушатели которого зарегистрированы для срабатывания в определенное время(а).

Эквиваленты

Запросы из других тем

Другие потоки приложения могут передавать некоторый код для выполнения в потоке диспетчеризации событий с помощью SwingUtilitiesвспомогательных классов (или EventQueueесли вы используете AWT ). Отправленный код должен быть обернут в Runnableобъект. Два метода этих классов позволяют:

  • синхронное выполнение кода ( SwingUtilities.invokeAndWait(Runnable)или EventQueue.invokeAndWait(Runnable))
  • и асинхронное выполнение кода ( SwingUtilities.invokeLater(Runnable)или EventQueue.invokeLater(Runnable))

из потока диспетчеризации событий.

Метод invokeAndWait()никогда не следует вызывать из потока диспетчеризации событий — это вызовет исключение . Метод SwingUtilities.isEventDispatchThread()или EventQueue.isDispatchThread()можно вызвать, чтобы определить, является ли текущий поток потоком диспетчеризации событий.

Код, предоставляемый посредством invokeLaterи invokeAndWaitв EDT, должен быть максимально быстрым, чтобы предотвратить зависание. Обычно они предназначены для доставки результата длительного вычисления в GUI (пользователю).

Рабочий шаблон дизайна

Выполнение задачи в другом потоке и представление результатов в EDT можно объединить с помощью шаблона проектирования worker . javax.swing.SwingWorkerКласс, разработанный Sun Microsystems , является реализацией шаблона проектирования worker и, начиная с Java 6, входит в стандартный дистрибутив Swing. SwingWorker обычно вызывается из прослушивателя событий, выполняемых EDT, для выполнения длительной задачи, чтобы не блокировать EDT.

Образцы

SwingWorker < Document , Void > worker = new SwingWorker < Document , Void > () { public Document doInBackground () выдает исключение IOException { return loadXML (); // тяжелая задача } public void done () { try { Document doc = get (); display ( doc ); } catch ( Exception ex ) { ex . printStackTrace (); } } }; worker . execute ();                                     

Если вы используете Groovy и groovy.swing.SwingBuilder, вы можете использовать doLater(), doOutside(), и edt(). Тогда вы можете записать это проще, вот так:

doOutside { def doc = loadXML () // тяжелая задача edt { display ( doc ) } }          

Эквиваленты

SwingWorker обычно создается EDT для длительных задач при обработке событий обратного вызова (прослушивателя). Создавая рабочий поток, EDT продолжает обработку текущего сообщения, не дожидаясь завершения рабочего потока. Часто это нежелательно.

Часто ваш EDT обрабатывает действие компонента GUI, которое требует от пользователя сделать выбор с помощью другого диалога, например JFileChooser, который всплывает, остается отзывчивым, пока пользователь выбирает свой вариант, и действие продолжается с выбранным файлом только после нажатия кнопки «ОК». Видите ли, это занимает время (пользователь отвечает в течение нескольких секунд), и вам нужен отзывчивый GUI (сообщения все еще закачиваются в EDT) в течение всего этого времени, пока EDT блокируется (он не обрабатывает более новые, например JFileChooser, сообщения в очереди до закрытия диалога и завершения текущего действия компонента). Порочный цикл разрывается, когда EDT входит в новый цикл сообщений, который отправляет сообщения как обычно, пока не придет «модальный диалог не завершится» и обычная обработка сообщений не возобновится с заблокированной позиции в действии компонента.

Проект Foxtrot с открытым исходным кодом эмулирует цикл сообщений Swing, обеспечивая «синхронный» механизм выполнения произвольных пользовательских задач, который выполняется только после того, как исполнитель завершит задачу.

 button.addActionListener ( new ActionListener () { public void actionPerformed ( ActionEvent e ) { button.setText ( " Спящий режим ... " ) ;       String text = null ; try { text = ( String ) Worker . post ( new Task () { public Object run () throws Exception { Thread . sleep ( 10000 ); return "Slept !" ; } }); } catch ( Exception x ) ...                      кнопка .setText ( текст ) ;что-тоЕще (); } });  

Начиная с версии Java 1.7, Java предоставляет стандартное решение для пользовательских вторичных циклов сообщений , предоставляя createSecondaryLoop () в системной EventQueue ().

Смотрите также

Ссылки

  1. ^ Эта проблема не является специфичной для Java Swing . Та же проблема существует в большинстве наборов инструментов Widget , например, в Windows Forms , где класс BackgroundWorker выполняет ту же функцию, что и SwingWorker в Java.
  2. ^ "The Event Dispatch Thread". Sun Microsystems . Получено 2011-10-02 .
  3. ^ "Отладка Swing - это действительно сложно?". Александр Поточкин. Архивировано из оригинала 2011-08-05 . Получено 2011-10-02 .
  4. ^ "Initial Threads". Sun Microsystems . Получено 2011-10-02 .
  5. ^ «Более строгие проверки нарушений EDT в Substance · Pushing Pixels».
  • javax.swing( Документация Javadoc по API Swing )
  • java.awt(документация Javadoc API AWT )
  • Документация API Swing
  • Поток диспетчеризации событий
  • Описание SwingWorker из руководства по Swing
  • Статья об обработке событий AWT/Swing о перекачке событий, диспетчеризации и обработке, а также EDT
  • Домашняя страница проекта Фокстрот
Получено с "https://en.wikipedia.org/w/index.php?title=Event_dispatching_thread&oldid=1215303331"