При работе с инструментарием виджетов очень важно понимать модель нитей, используемую для чтения и диспетчеризации событий GUI платформы. Реализация нити пользовательского интерфейса влияет на правила, которым должны следовать приложения при работе с нитями Java.
В GUI любого приложения, независимо от языка и инструментария UI, платформа ОС обнаруживает события GUI и помещает их в очереди событий приложения. Несмотря на то, что на различных платформах эта технология слегка отличается, основной принцип все равно один и тот же. Когда пользователь щелкает мышью, вводит символ или вызывает окно, ОС генерирует события GUI приложения: щелчок мышью, нажатие клавиши или события прорисовки окна. Она определяет, какому окну или приложению соответствует то или иное событие, и помещает события в очередь соответствующего приложения.
Базовая структура для любого приложения с оконным интерфейсом - это цикл обработки событий. Приложение инициализирует, а затем запускает цикл, который просто считывает события GUI из очереди и реагирует на них соответствующим образом. Любые действия, выполняемые во время обработки одного из этих событий, должны выполняться как можно быстрее, чтобы система GUI оставалась способной отвечать пользователю.
Длительные операции, инициируемые событиями UI, должны выполняться в отдельной нити. Это делается для того, чтобы нить цикла обработки событий могла быстро вернуться и извлечь из очереди приложения следующее событие. Однако доступ к виджетам и API платформы из других нитей должен управляться с помощью явных блокировок и сериализации. Приложение, в котором эти правила не соблюдаются, может привести к ошибке в ОС или, хуже того, заблокировать всю систему GUI.
Модель управления нитями в SWT строится на принципе поддержки непосредственно платформой. Прикладная программа запускает в своей главной нити цикл событий и извлекает события прямо из нее. Нить пользовательского интерфейса - это нить, в которой был создан виджет класса Display. Все остальные виджеты должны создаваться в этой же нити.
Так как код всех событий инициируется из нити UI приложения, то код приложения, обрабатывающий события, может свободно обращаться к виджетам и работать с графикой без каких-либо дополнительных приемов. Но именно приложение отвечает за порождение вычислительных нитей, выполняющих в ответ на событие длительные операции.
Примечание: Для любого вызова, который должен был быть сделан из нити UI, а выполняется из другой нити, SWT генерирует исключительную ситуацию SWTException.
Главная нить, включающая цикл событий, для приложения SWT имеет следующую структуру:
public static void main (String [] args) { Display display = new Display (); Shell shell = new Shell (display); shell.open (); // start the event loop. We stop when the user has done // something to dispose our window. while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); } display.dispose (); }
После создания виджетов и открытия оболочки приложение читает и координирует события из очереди ОС, пока окно оболочки не закроется. Если в данной очереди нет событий, то окно засыпает, чтобы могли выполняться другие приложения.
SWT предоставляет специальные методы доступа для вызова виджетов и графического кода из фоновой нити.
Приложения, требующие вызова кода UI не из нити UI, должны поддерживать метод Runnable, вызывающий код UI. Для выполнения этого кода в нити UI во время цикла событий служат методы syncExec(Runnable) и asyncExec(Runnable) класса Display.
В следующем фрагменте кода показан образец использования этих методов:
// долгие вычисления ... // теперь обновляется UI. Нам не важен результат, // поэтому используем async. display.asyncExec (new Runnable () { public void run () { if (!myWindow.isDisposed()) myWindow.redraw (); } }); // продолжаем вычисления ...
При использовании asyncExec желательно всегда проверять, существует ли виджет, т.к. между вашими вызовами в нити пользовательского интерфейса могут произойти любые события.
Правила управления нитями достаточно просты при реализации приложения SWT с нуля, так как вы управляете созданием цикла событий и принимаете решение о порождении вычислительных нитей в приложении.
Однако при создании модуля рабочей среды все немного усложняется. Ниже приводятся некоторые правила применения классов пользовательского интерфейса, но помните, что периодически, от выпуска к выпуску, из них могут появляться исключения: