Cuando se trabaja con un juego de herramientas de widget, es importante entender el modelo de hebra subyacente utilizado para leer y enviar eventos de GUI de la plataforma. La implementación de la hebra de UI afecta a las normas 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 UI, la plataforma de 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 ventanas, el OS genera eventos de GUI de la aplicación, como pulsaciones de ratón, pulsaciones de tecla o ilustraciones de ventana. Determina qué ventana (y aplicación) debe recibir el evento y lo coloca en la cola de eventos de la aplicación.
La estructura subyacente para cualquier aplicación de GUI en ventanas es un bucle de evento. Las aplicaciones inicializan y, a continuación, inician un bucle que sólo lee los eventos de GUI de la cola y actúa consecuentemente. Cualquier trabajo efectuado mientras se maneja uno de estos eventos debe realizarse rápidamente a fin de mantener la respuesta del sistema de GUI al usuario.
Las operaciones largas activadas por eventos de UI deben efectuarse en una hebra aparte al objeto de que la hebra de bucle de eventos esté preparada rápidamente para 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 sigue las normas puede ocasionar una llamada de OS errónea, 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, muchos juegos de herramientas de widget de alto nivel de Java suelen intentar proteger a los desarrolladores de la aplicación contra los aspectos 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 pone ninguna restricción al ritmo con que la aplicación maneja los eventos. Las aplicaciones deben seguir utilizando procedimientos de bloqueo especiales para acceder al código de UI desde su hebra; esto se lleva a cabo de manera coherente mediante 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" a 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 de Java y del rendimiento de las aplicaciones.
Las plataformas de GUI actuales efectúan muchas optimizaciones con la cola de eventos. Una optimización común es colapsar múltiples eventos de ilustración en la cola. Cada vez que debe ilustrarse parte de una ventana, se puede comprobar que en la cola no existan eventos de solapamiento o de ilustración redundante que aún no se han enviado. Estos eventos pueden fusionarse en un evento de ilustración, haciendo que la ejecución del código de ilustración de la aplicación sea menos vacilante y menos frecuente. Esta optimización no será satisfactoria si el juego de herramientas del widget saca los eventos de la cola rápidamente y los coloca en una cola interna.
Cambiar el punto de vista del desarrollador con respeto al modelo de hebra ocasiona confusión a los programadores con experiencia en la programación del sistema de GUI nativa utilizandootros lenguajes y juegos de herramientas.
SWT sigue el modelo de hebras que las plataformas soportan directamente. El programa de aplicación ejecuta el bucle de eventos en su hebra principal y los envía directamente desde esta hebra. Se trata de la "hebra de UI" de la aplicación.
Nota: Técnicamente, la hebra de UI es la hebra que crea 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 activa 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 gráficas sin ninguna técnica especial. Sin embargo, la aplicación es responsable de efectuar fork en hebras de cálculo cuando se realizan operaciones largas como respuesta a un evento.
Nota: SWT activará SWTException para todas las llamadas efectuadas desde una hebra que no es de UI, la cual debe haberse creado a partir de una hebra de UI.
La hebra principal, incluido el bucle de eventos, para 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. Parar cuando el usuario ha realizado
// alguna operación para desechar la ventana.
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
Una vez se han creado los widgets y abierto el shell, la aplicación lee y envía eventos desde la cola del OS hasta que se desecha la ventana del 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 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 varias 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 widgets y de gráficos desde una hebra de segundo plano.
Las aplicaciones que desean llamar a código de UI desde una hebra que no es de UI, deben proporcionar 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 en el momento adecuado.
El siguiente segmento de código muestra el patrón para utilizar estos métodos.
// efectuar cálculos intensivos
...
// actualizar la UI ahora. Como el resultado no es determinante,
// se puede efectuar de manera asíncrona.
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
myWindow.redraw();
}
});
// efectuar más cálculos ahora
...
Las normas relacionadas con las hebras son muy claras cuando se implementa una aplicación de SWT desde el principio, porque controla la creación del bucle de eventos y la decisión de efectuar fork en las hebras de cálculo de la aplicación.
¿Cuáles son las reglas si se contribuye con código de conector al entorno de trabajo? Afortunadamente, no existen ninguna "solución mágica" para las hebras oculta en el código de JFace o de entorno de trabajo. Las reglas son claras.