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 SO 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.
Los programadores de la GUI nativa que utilizan C tienen ciertos conocimientos sobre diseño para trabajar con el bucle de eventos de la plataforma. Sin embargo, los juegos de herramientas de widgets de alto nivel de Java suelen intentar proteger a los desarrolladores de la aplicación contra los problemas de hebras de UI ocultando el bucle de eventos de la plataforma.
Una manera común de llevar esto a cabo es establecer una hebra de UI de juego de herramientas dedicada con la finalidad de leer y enviar eventos desde el bucle de eventos y colocarlos en una cola interna mantenida por aplicaciones que ejecutan hebras separadas. Esto permite al juego de herramientas responder con tiempo suficiente al sistema operativo, a la vez que no se impone ninguna restricción al ritmo con que la aplicación maneja los eventos. Las aplicaciones deben seguir utilizando técnicas de bloqueo especiales para acceder al código de UI desde su hebra; esto se lleva a cabo de manera coherente en todo el código, ya que todo el código de una aplicación se ejecuta en una hebra que no es de UI.
Aunque puede parecer interesante "proteger" las aplicaciones contra los aspectos de las hebras de UI, en la práctica puede ocasionar muchos problemas.
Resulta difícil depurar y diagnosticar problemas cuando el ritmo de los eventos de GUI depende de la implementación de hebras Java y del rendimiento de las aplicaciones.
Las plataformas de GUI actuales efectúan muchas optimizaciones en la cola de eventos. Una optimización común es reducir los eventos de pintura consecutivos de la cola. Cada vez que debe pintarse de nuevo una parte de una ventana, se puede comprobar si en la cola existen eventos de pintura solapados o redundantes que aún no se han enviado. Estos eventos pueden fusionarse en un solo evento de pintura, haciendo que la ejecución del código de pintura de la aplicación sea menos vacilante y menos frecuente. Esta optimización no será satisfactoria si el juego de herramientas de widgets retira los eventos de la cola rápidamente y los envía a una cola interna.
El hecho de cambiar la manera en que el desarrollador percibe el modelo de hebras provoca confusión en los programadores que tienen experiencia en la programación del sistema de la GUI nativa utilizando otros lenguajes y juegos de herramientas.
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. Esta es la "hebra de UI" de la aplicación.
Nota: técnicamente, la hebra de UI es la que crea el objeto Display. En la práctica, también es la hebra que ejecuta el bucle de eventos y crea los widgets.
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 las llamadas que se realicen desde una hebra que no sea de UI, la cual debe haberse creado a partir de una hebra de UI.
La hebra principal, incluido el bucle de eventos, de una aplicación de SWT tiene este aspecto:
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.
Nota: el modelo de hebras más habitual para una aplicación de SWT es ejecutar una sola hebra de UI y efectuar operaciones largas en las hebras de cálculo. Sin embargo, SWT no impone a los desarrolladores la utilización de este modelo únicamente. Una aplicación podría ejecutar múltiples hebras de UI, con un bucle de eventos diferente en cada hebra.
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 permiten ejecutar estos ejecutables en la hebra de UI en el momento adecuado.
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.getDefault ().asyncExec (new Runnable () { public void run() { myWindow.redraw(); } }); // efectuar más cálculos ahora ...
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.
Si añade código de conector al entorno de trabajo, no existe para las hebras ninguna "solución mágica" oculta en el código de JFace o del entorno de trabajo. Las reglas son muy sencillas: