Cuando se trabaja con un juego de herramientas de widgets, es importante entender el modelo de hebras subyacente utilizado para leer y despachar los eventos de la GUI de la plataforma. La implementación de la hebra de la UI afecta a las reglas que las aplicaciones deben seguir al utilizar hebras Java en su código.
En cualquier aplicación de GUI, independientemente del lenguaje o del juego de herramientas de la UI, la plataforma del OS detecta eventos de GUI y los coloca en colas de eventos de la aplicación. Aunque los mecanismos son ligeramente diferentes en las distintas plataformas de OS, los conceptos básicos son parecidos. A medida que el usuario pulsa el ratón, escribe caracteres o se desplaza por las ventanas, el OS genera eventos de la GUI de la aplicación, como son las pulsaciones del ratón, las pulsaciones de teclas o las pinturas de ventana. Determina qué ventana y aplicación debe recibir cada evento y lo coloca en la cola de eventos de la aplicación.
La estructura subyacente para cualquier aplicación de GUI con ventanas es un bucle de eventos. Las aplicaciones inicializan y, a continuación, inician un bucle que tan solo lee los eventos de la GUI de la cola y responde en consecuencia. Cualquier trabajo efectuado mientras se maneja uno de estos eventos debe realizarse rápidamente para que el sistema de la GUI siga respondiendo al usuario.
Las operaciones largas desencadenadas por los eventos de la UI deben efectuarse en una hebra aparte con el fin de permitir que la hebra del bucle de eventos retorne rápidamente y vaya a buscar el siguiente evento de la cola de la aplicación. Sin embargo, el acceso a los widgets y a la API de la plataforma desde otras hebras debe controlarse mediante un bloqueo y una serialización explícitos. Una aplicación que no siga las reglas puede hacer que falle una llamada del OS o, aún peor, que todo el sistema de la GUI quede bloqueado.
SWT sigue el modelo de hebras soportado directamente por las plataformas. El programa de aplicación ejecuta el bucle de eventos en su hebra principal y los envía directamente desde esta hebra. La hebra de UI es la hebra en que se creó Display. Todos los demás widgets deben crearse en la hebra de UI.
Puesto que todo el código de eventos se desencadena desde la hebra de UI de la aplicación, el código de aplicación que maneja eventos puede acceder libremente a los widgets y efectuar llamadas a los gráficos sin ninguna técnica especial. Sin embargo, la aplicación es responsable de bifurcar (método fork) las hebras de cálculo cuando se realizan operaciones largas como respuesta a un evento.
Nota: SWT desencadenará una SWTException para cualquier llamada realizada desde una hebra que no sea de UI, que debe haberse creado a partir de la hebra de UI.
La hebra principal, incluido el bucle de eventos, de una aplicación de SWT tiene la siguiente estructura:
public static void main (String [] args) { Display display = new Display (); Shell shell = new Shell (display); shell.open (); // iniciar el bucle de eventos. Nos detenemos cuando el usuario haya terminado // una tarea para desechar nuestra ventana. while (!shell.isDisposed ()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose (); }
Una vez creados los widgets y abierta la shell, la aplicación lee y envía eventos desde la cola del OS hasta que se desecha la ventana de la shell. Si no existen eventos disponibles en la cola, se indicará a la pantalla que no dé a otras aplicaciones la posibilidad de ejecutarse.
SWT proporciona métodos de acceso especiales para llamar al código de los widgets y gráficos desde una hebra de segundo plano.
Las aplicaciones que se disponen a llamar a código de UI desde una hebra que no es de UI, deben proporcionar un objeto Runnable para llamar al código de UI. Los métodos syncExec(Runnable) y asyncExec(Runnable) de la clase Display se utilizan para ejecutar estos ejecutables en la hebra de UI durante el bucle de eventos.
El siguiente fragmento de código muestra el patrón para utilizar estos métodos:
// efectuar cálculos intensivos ... // ahora actualizar la UI. No dependemos del resultado, // por lo que se puede efectuar de manera asíncrona. display.asyncExec (new Runnable () { public void run() { if (!myWindow.isDisposed()) myWindow.redraw(); } }); // efectuar más cálculos ahora ...
Es una buena práctica el comprobar si se ha desechado el widget desde el
ejecutable al utilizar asyncExec. Dado que pueden ocurrir otras cosas en la
hebra de UI entre la llamada a asyncExec
y la ejecución del
ejecutable, nunca podrá estar seguro del estado en que se encontrarán los
widgets cuando se ejecute el ejecutable.
Las reglas relacionadas con las hebras son muy claras cuando se implementa una aplicación de SWT desde cero, ya que se controla la creación del bucle de eventos y la decisión de bifurcar las hebras de cálculo de la aplicación.
Todo se complica un poco más cuando se contribuye con código de conector al entorno de trabajo. Las reglas siguientes pueden considerarse como "reglas de compromiso" si se utilizan clases de UI de plataforma, aunque de un release a otro puede haber excepciones a estas reglas: