114
EL ARCHIPIÉLAGO ECLIPSE (PARTE 4 DE 4) Miguel Ángel Abián

Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

Embed Size (px)

DESCRIPTION

Esta serie de artículos expone qué es Eclipse, cuál es su estructura, en qué se diferencia o se asemeja a otros productos ya existentes, cuáles son sus ventajas e inconvenientes, cuál podría ser su utilidad para los desarrolladores (centrándose en la comunidad Java), qué estrategias empresariales subyacen bajo el proyecto Eclipse y cuál podría ser su futuro. Este artículo es un tutorial sobre SWT (Standard Widget Toolkit), con ejemplos y código fuente. Autor: Miguel Ángel Abián Publicado originalmente en javaHispano.

Citation preview

Page 1: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

EL ARCHIPIÉLAGO ECLIPSE

(PARTE 4 DE 4)

Miguel Ángel Abián

Page 2: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 2 de 114

EL ARCHIPIÉLAGO ECLIPSE (PARTE 4 DE 4)

Fecha de última revisión: 27.05.2014

Miguel Ángel Abián mabian ARROBA aidima PUNTO es

Conozco máquinas que son más complicadas que la gente.

Thomas Pynchon. V

La gente suele preguntarme: “¿Por qué escribe usted en una lengua moribunda?”. Esa

pregunta tiene varias respuestas. En primer lugar, me gusta escribir historias de fantasmas,

y para eso nada hay más adecuado que una lengua moribunda. Cuanto más muerta está una

lengua, más vivo está el fantasma. A los fantasmas les encanta el yiddish y, por lo que sé,

todos lo hablan. [...] Por otra parte, el yiddish puede ser una lengua moribunda, pero es la

única que conozco bien. Fue la lengua de mi madre, y ustedes saben que una madre nunca

está realmente muerta.

I. B. Singer. Discurso en la ceremonia de entrega de los premios Nobel (1978)

En 1968, los Beatles publicaron el doble disco conocido como el Álbum blanco. Visto en retrospectiva, el disco es el testimonio de un grupo que había dejado atrás los alaridos de las fans y que estaba buscando su propia voz, lejos de la psicodelia y del rock and roll. En el Álbum blanco hay de todo, como en un bazar: confusión (musical y personal), pop, rock'n'roll, distorsión, experimentación (musical y comercial), baladas, aullidos. No obstante, el disco no es un caos informe ni un revoltijo desconcertante: hay un cierto orden interno, una cierta coherencia. Los Beatles no siguieron el camino esbozado en este disco, bien porque los conflictos personales estaban destrozando a la banda, bien porque ese camino no coincidía con lo que la gente esperaba de un grupo tan conocido.

Eclipse me recuerda mucho al Álbum blanco. La plataforma Eclipse tiene de todo: uno puede trabajar, entre otros lenguajes, con Java, C/C++, PHP, JavaScript, Ruby, Pascal, Eiffel, Python y COBOL (el no muerto, el Nosferatu de los lenguajes informáticos: espero que nunca le muerda). Nadie le impide agregar a Eclipse los plug-ins (extensiones) que desee y trabajar con un magnífico IDE, hecho a medida, para ASP, JSP, XML, XHTML o HTML. Es más, puede escribir sus propios plug-ins y comercializarlos. Tantas posibilidades no se traducen –por ahora– en un Helter Skelter: la comunidad de desarrolladores y los publicistas que rodean a Eclipse están trabajando mucho y muy bien, con metas muy claras. Con todo, hay mucho de experimentación, en este caso informática y comercial, dentro y alrededor de Eclipse.

Copyright (c) 2005 -2014, Miguel Ángel Abián . Este documento puede ser distribuido sólo bajo los términos y condiciones de la licencia de Documentación de javaHispano v1.0 o posterior (la última versión se encuentra en http://www.javahispano.org/licencias/).

Page 3: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 3 de 114

Al proyecto Eclipse le deseo mejor suerte que los Beatles tras el Álbum blanco. Si el proyecto se fragmenta en exceso, es posible que a los subproyectos les ocurra lo mismo que a los componentes del grupo. A saber: que ninguno alcanzó la popularidad y el reconocimiento que habían tenido cuando estaban unidos.

John Lennon dijo en 1980, poco antes de morir: “Si los años sesenta o los Beatles tenían un mensaje, era aprender a nadar. Y una vez has aprendido, nadar”. Esta serie de artículos es una rápida lección de natación, impartida con un solo fin: invitarle, si no lo ha hecho ya, a zambullirse en las aguas del océano Eclipse. No tiene nada que perder, y sí mucho que ganar.

14. SWT: el nuevo componente gráfico para Java

El Standard Widget Toolkit (SWT) de la plataforma Eclipse ha sido el aspecto de Eclipse que mayores rechazos, adhesiones y controversias ha provocado en la comunidad de Java. SWT constituye la respuesta de IBM, para el desarrollo de interfaces de usuario, a AWT y a Swing (la historia de SWT y su papel en la estrategia comercial de IBM se explicarán en la próxima parte de esta serie de artículos). De acuerdo con la documentación oficial de Eclipse, he aquí la descripción del componente Standard Widget Toolkit: "El componente SWT está diseñado para proporcionar acceso eficaz y transportable a los servicios de interfaz de usuario del sistema operativo sobre el cual se implementa". Dicho de otra manera, también oficial: “[SWT es] un conjunto de componentes gráficos y una biblioteca gráfica integrada con el sistema de ventanas específico del sistema operativo, pero con una API independiente del SO”. Tanto SWT como JFace son bibliotecas estructuradas en paquetes con clases e interfaces escritas en Java.

Widget es una palabra inglesa que se usa para referirse a un dispositivo cuyo nombre no se conoce o no importa, o bien a un dispositivo que todavía no existe; una traducción aproximada sería cachivache o trasto. Chocaría mucho leer frases como “el cachivache pequeño se coloca en el centro del cachivache grande” en un artículo técnico en español; en cambio, en inglés suenan incluso simpáticas.

La documentación oficial de Eclipse (http://www.eclipse.org) establece que un widget es “cualquier objeto de la interfaz gráfica de usuario que puede colocarse dentro de otro widget” (versión tecnológica de la frase “Una gallina es lo que usan los huevos para producir otros huevos”; el ser humano no ha avanzado mucho explicando las cosas, la verdad). Veamos una definición más aclaratoria: “Un widget es un objeto de la interfaz gráfica de usuario, responsable de la interacción con el usuario”.

En la documentación y la bibliografía de Eclipse suelen usarse de manera intercambiable las palabras widget y control (elemento de la interfaz gráfica con contrapartida en el sistema operativo; es decir, gestionado por el SO). Esta equivalencia no resulta del todo cierta, pues no todos los widgets son controles. Consideremos, vaya por caso, un control de tipo árbol: sus nodos y subnodos son widgets (elementos de la interfaz gráfica), pero no controles. La razón para esto es práctica: si el árbol se encarga de dibujar los nodos y subnodos, se evita consumir los recursos del sistema operativo que se necesitarían si cada nodo fuera un control.

Page 4: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 4 de 114

Suele decirse que Swing es un componente de “peso ligero” (lightweight), mientras que SWT y AWT son de “peso pesado” (heavyweight). Aunque el significado de estos términos dista mucho de ser unánime, suele aceptarse que “peso ligero” significa que hay una asociación o correspondencia uno a uno (one-to-one mapping) entre los widgets del componente y los de la plataforma (controles). Un componente de peso pesado simplifica mucho la programación gráfica: todas las implementaciones de los sucesos (apretar una tecla, mover el ratón...) vienen dadas por el sistema operativo, mejor dicho, por el gestor de ventanas del sistema operativo. Su principal desventaja radica que consume muchos recursos del sistema operativo (memoria, punteros, ciclos de CPU). Consideremos, por ejemplo, que creamos un objeto java.awt.Button: al instante, el gestor de ventanas del SO creará su propio botón. Cuando el usuario pulse el botón, el suceso irá, primero, de la biblioteca gráfica del SO a la máquina virtual de Java; luego, irá a la lógica vinculada al objeto Button de AWT, que decidirá qué hay que hacer.

En un componente de peso ligero, los widgets son dibujados por el componente, no por el SO. En consecuencia, cada componente debe encargarse de implementar sucesos como mover el ratón o apretar una tecla. A cambio, su rendimiento resulta, en general, mejor que el de uno pesado (en cuanto a recursos, es más facil y menos exigente dibujar widgets que dejar que los cree el SO). Consideremos, por ejemplo, una ventana con cien o doscientas etiquetas. En Swing, la ventana (un JFrame) se comportará mejor que en AWT o SWT, pues las etiquetas se dibujan sobre la ventana y, por tanto, no hay que preocuparse por liberar sus recursos (son dibujos). En estos dos últimos componentes gráficos, las etiquetas serán creadas por el SO, que tendrá que conservarlas en memoria en todo momento y supervisar sus sucesos y el estado de cada una.

Otro ejemplo: consideremos una tabla con un millón de filas. En Swing, el tiempo que se tardaría en dibujarla apenas diferiría del empleado para dibujar una tabla de diez mil filas. En SWT, el tiempo que se tardaría en dibujar la tabla de un millón de filas sería de dos órdenes de magnitud superior al necesario para dibujar la tabla de diez mil filas, pues cada fila sería un widget mantenido por el sistema operativo (omito aquí cualquier consideración sobre la memoria que emplearía SWT). Por regla general, la escalabilidad de los componentes de peso ligero es mucho mayor que la de los componentes de peso pesado.

¿Es SWT un AWT con muchos más widgets? Por fuera, sí; pero por dentro hay

muchas diferencias. Tanto AWT como SWT usan las funciones de la API gráfica de las plataformas donde se ejecutan, pero lo hacen de modo muy distinto. AWT usa un sistema de componentes “gemelos” donde cada widget AWT tiene asociado un componente en el gestor de ventanas del sistema operativo. Cada widget AWT tiene asociado código nativo, escrito en C o C++, que hace llamadas a las bibliotecas gráficas de la plataforma (en Windows, Win32 o MFC) y que controla el comportamiento de los widgets. En cada JDK (Java Distribution Kit) se incluyen las clases Java de AWT y el código máquina resultante de compilar el código nativo (el código máquina cambia para cada plataforma, pero no las clases Java).

De resultas del diseño basado en componentes gemelos, AWT tiene un número muy limitado de widgets, pues sólo puede incluir componentes presentes en todas las plataformas donde se implementa. Por ejemplo, no hay un widget árbol en AWT, pues no existe en Motif y, por tanto, en esa plataforma no hay un componente gemelo árbol al que AWT puede llamar.

En SWT, los widgets están escritos en Java, no en código nativo; y los métodos gráficos de la plataforma se llaman a través de una “capa” que se explicará más adelante. Para cada plataforma, esta capa expone los métodos de la API (interfaz de

Page 5: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 5 de 114

programación de aplicaciones) gráfica de la plataforma, de suerte que las clases SWT (escritas en Java) pueden llamar a los métodos de la API gráfica. A diferencia de AWT, las clases SWT cambian en cada plataforma. Aparte de que hay muchos más widgets en SWT que en AWT, la gran ventaja de SWT es que toda la lógica de los widgets está escrita en Java (en AWT, la lógica está mezclada con código nativo de cada plataforma).

El propósito original de Swing consistía en proporcionar a las aplicaciones escritas

en Java el mismo aspecto en todas las plataformas (con la posibilidad de imitar hasta cierto punto la apariencia propia de cada una). Aunque con Swing pueden producirse, con esfuerzo, aplicaciones en Java de aspecto similar a las aplicaciones propias de cada plataforma, su rendimiento siempre ha sido pobre. Resulta destacable que Swing haya mejorado bastante su eficacia en las versiones 1.4 y 5.0 (antes 1.5) de Java. Posiblemente, la competencia que supone SWT ha influido beneficiosamente en el desarrollo de Swing.

El motivo del pobre rendimiento con Swing radica en que el código que interacciona directamente con los widgets de cada plataforma está escrito en C o C++ (forma parte de las bibliotecas de AWT específicas de cada plataforma) y, en consecuencia, no está disponible para Swing, que está escrito en Java. También la API que proporcionan los widgets propios de cada plataforma está escrita en C o C++, y Swing no puede acceder directamente a ella. Por estos motivos, Swing trabaja con la API gráfica que le proporciona AWT. En Swing, cada componente es dibujado como una imagen en el componente que lo contiene, lo que requiere que Swing trabaje bit a bit con las interfaces gráficas. Cuando se quiere mostrar una interfaz al usuario, Swing –a través de AWT– envía el mapa de bits correspondiente al gestor de ventanas propio de la plataforma donde se trabaja. Como puede suponerse, este planteamiento dista mucho de ser eficaz; sus limitaciones se aprecian enseguida en dispositivos como agendas electrónicas o teléfonos móviles, donde la memoria está muy limitada.

En cuanto a la personalización de los controles Swing para cada plataforma (lo que se conoce como pluggable look and feel o pluggable L&F), los resultados han sido sumamente mediocres: en parte porque la apariencia no coincide exactamente con la que deberían tener, y en parte porque Sun no ha ido actualizando Swing a las nuevas versiones de los sistemas operativos. Así, por ejemplo, la apariencia y sensación de Windows (Windows L&F) que proporciona Swing ha sido (hasta la versión 1.4.2 de Java) la misma para Windows 95, Windows 98, Windows 2000, Windows Millenium (curioso experimento fallido, por cierto) y Windows XP. Como usted mismo habrá comprobado, la apariencia de las aplicaciones para Windows cambiaba, y mucho, de una versión del sistema operativo a otro.

En comparación con Swing, el SWT de Eclipse ha roto las reglas del juego

mediante el empleo de una estrategia sumamente ingeniosa y eficaz: usa la API JNI de Java (Java Native Interface, interfaz nativa de Java). JNI permite que los programas en Java llamen a métodos nativos (métodos propios de la plataforma, generalmente escritos en C o C++) y que reciban los resultados que éstos devuelven. Cuando se compila un archivo con código JNI-C (código en C donde se implementan métodos declarados de tipo JNI), se genera una biblioteca compartida –en Windows, una DLL o biblioteca de enlace dinámico–, que permite acceder desde Java a los métodos declarados en el código JNI-C.

Para ilustrar cómo se trabaja con JNI, considero aquí el ejemplo de un método nativo que calcula números de Fibonacci.

En primer lugar, el método nativo se declara en una clase llamada MetodoNativo:

Page 6: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 6 de 114

public class MetodoNativo { // declaración Java del método public native int fibonacci(int n); // Carga la biblioteca compartida llamada native. static { System.loadLibrary("native"); } }

En segundo lugar, se compila la clase anterior y, luego, se usa la herramienta javah

de la siguiente forma (omito cualquier consideración sobre el CLASSPATH):

javah –jni MetodoNativo Con el paso anterior, se crea un archivo MetodoNativo.h que contiene lo siguiente: /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class MetodoNativo */ #ifndef _Included_MetodoNativo #define _Included_MetodoNativo #ifdef __cplusplus extern "C" { #endif /* * Class: MetodoNativo * Method: fibonacci * Signature: (I)I */ JNIEXPORT jint JNICALL Java_MetodoNativo_fibonacci (JNIEnv *, jobject, jint); #ifdef __cplusplus } #endif #endif En tercer lugar, la implementación en C del método fibonacci() se guarda en un

archivo ImplementacionMetodoNativo.c: #include <jni.h> #include “MetodoNativo.h” /* implementación en C de la función que calcula el énesimo número de Fibonacci */ int fibonacci(int n) { if (n <= 1) return 0; if (n == 2) return 1;

Declaración del método Java_MetodoNativo_fibonacci().

El argumento JNIEnv* es un puntero al entorno de

ejecución del método.

El argumento jobject es una referencia a la clase donde se

especifica el método (MetodoNativo.java)

El argumento jint es el tipo C que corresponde al tipo

Java int, declarado como tipo de retorno del método

fibonacci ().

Page 7: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 7 de 114

return (fibonacci(n-1) + fibonacci(n –2)); } /* implementación de Java_MetodoNativo_fibonacci() */ JNIEXPORT jint JNICALL Java_MetodoNativo_fibonacci(JNIEnv *env, jobject obj, jint n) { return fibonacci(n); } Por último, el archivo anterior se compila con un compilador de C o C++, que creará

un biblioteca compartida (en Windows, una DLL). A partir de ese momento, el método nativo fibonacci() podrá usarse desde cualquier clase de Java.

La técnica que usa SWT para llamar –mediante JNI– a las API gráficas de cada

sistema operativo (escritas en C o C++) consiste en establecer, siempre que sea posible, una correspondencia uno a uno entre los métodos en Java de cada widget SWT y las llamadas a la API gráfica propia de cada sistema operativo. Más adelante, veremos código JNI-C de SWT donde se aprecia esa correspondencia.

Las razones por las que SWT se basa en dicha estrategia son tres: eficacia, velocidad e integración con la plataforma. Un widget SWT llama directamente al gestor de ventanas específico de la plataforma; así se evita que Java tenga que enviar, mediante AWT, las interfaces en forma de mapas de bits. Con SWT se logra una integración casi completa con cada plataforma. No olvidemos que la integración con la plataforma no se reduce a la apariencia y la sensación (L&F): características como “copiar y pegar” o “arrastrar y soltar” son automáticas si se usa el SWT, pero no lo son tanto si se usa Swing. Pese al tiempo transcurrido desde que salieron las primeras versiones de Swing, aún existen acciones que no producen en algunas plataformas los resultados que esperaría el usuario habituado a éstas.

Tal es la integración de SWT con la plataforma, que refleja inmediatamente los cambios en la apariencia y sensación de la interfaz de usuario del sistema operativo subyacente. Así, un cambio de piel (skin) de Windows XP provocará que todas las interfaces de usuario construidas con componentes SWT cambien al instante su apariencia y sensación. Una piel o skin es un conjunto de gráficos que incluye todas las piezas necesarias para cambiar el aspecto y sensación de la interfaz gráfica. Los gráficos pueden incluir imágenes para botones, barras, menús, etc. Skinning es la acción de aplicar una piel. Cuando se aplica una piel a Windows, se altera su apariencia y sensación: cambian los colores, los botones, etc. (El término skinning se usó originalmente en el videojuego Quake , juego tremendamente popular por su carácter intimista y conciliador. Para dar variedad al juego se inventaron varias pieles, que permitían al usuario cargar una serie de gráficos que cambiaban la apariencia del personaje principal, un pacífico y sosegado ciudadano.)

La integración no se detiene en la apariencia y la sensación de Windows: SWT permite trabajar con los objetos binarios reutilizables de Microsoft (COM). De hecho, con unas pocas llamadas a métodos SWT se puede incluir controles ActiveX y documentos OLE en las aplicaciones SWT.

La declaración del método Java_MetodoNativo_fibonacci() en

ImplementacionMetodoNativo.c debe coincidir con la del método

Java_MetodoNativo_fibonacci() en MetodoNativo.h.

Page 8: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 8 de 114

Figura 14. Bloc de notas visto con distintas pieles de Windows. Se ha utilizado

la herramienta WindowBlinds 3, disponible en http://www.windowblinds.net

SWT usa los widgets propios de cada plataforma siempre que sea posible, excepto

cuando uno no existe en todas las plataformas. En ese caso, SWT lo simula en las plataformas que no cuentan con él. Dicho de otro modo: SWT usa para los widgets un enfoque basado en el mínimo común denominador. Por ejemplo, Motif no proporciona por omisión un widget de tipo árbol; consecuentemente, el SWT proporciona un widget árbol con la misma API que la implementación propia de Windows. Ningún usuario de Motif notará nada raro cuando use un componente SWT árbol: como éste no existe de serie en Motif, el usuario carecerá de ideas preconcebidas sobre cómo debe comportarse (salvo que provenga de Windows). A diferencia de AWT, SWT proporciona todos los controles que se suponen imprescindibles en cualquier interfaz gráfica moderna.

Page 9: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 9 de 114

Una vez obtenida la correspondencia uno a uno entre los métodos en Java y los métodos propios de la API gráfica de la plataforma, el desarrollador puede olvidarse del código JNI-C y de los detalles de bajo nivel del sistema operativo, y limitarse a utilizar los métodos públicos que proporcionan las clases de SWT. Por así decirlo, simplificando un poco, SWT encapsula de modo transparente el sistema operativo mediante JNI, permitiendo así utilizar todas las características de los widgets propios de cada plataforma. Actúa, en definitiva, como una fina capa entre Java y las bibliotecas de la API gráfica específica de cada SO. En comparación con Swing, SWT evita el uso de una capa gruesa y ralentizadora como la de AWT (veáse la figura 15).

Casi todo el código de las clases SWT se limita a actuar como “puente” entre el

mundo de Java y el de la plataforma: excepto en el caso de los componentes SWT sin equivalente en la plataforma, apenas se almacena información sobre los componentes SWT. No hace falta mucho más: SWT usa, siempre que puede, la información que proporciona la API gráfica de cada plataforma.

Cualquier aplicación escrita en Java podría utilizar la JNI para establecer una correspondencia entre los métodos Java y las capacidades gráficas propias de la plataforma usada. La ventaja de usar SWT radica en que evita a los programadores escribir su propio código JNI (tarea que, desde luego, dista mucho de ser trivial y requiere un buen conocimiento de la plataforma con la cual se trabaja).

Fig. 15. Funcionamiento interno de los dos componen tes gráficos

Componente gráfico Swing AWT

Biblioteca gráfica del SO

Swing

Componente gráfico SWT

Biblioteca gráfica del SO

JNI-CSWT

Miguel Ángel Abián, marzo de 2005

escrito en C escrita en Cescrito en Java

escrito en Java escrita en C

r

FUNCIONAMIENTO INTERNO DE SWING y SWT

Page 10: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 10 de 114

Para ver cómo funcionan en SWT los métodos JNI, podemos considerar el método setMenu() de la clase Java OS (clase que representa el sistema operativo de la plataforma y que forma parte de SWT):

public static final native boolean SetMenu (int hWnd, int hMenu);

Este método asigna un menú a una ventana. La palabra reservada native indica al

compilador de Java dos cosas: a) la implementación del código no está escrita en Java; b) la implementación se guarda en un archivo (os.c) que no es el de la clase OS (os.java). En Windows, el código JNI-C correspondiente al método setFocus() es

JNIEXPORT jboolean JNICALL OS_NATIVE(SetMenu) (JNIEnv *env, jclass that, jint arg0, jint arg1) { jboolean rc = 0; OS_NATIVE_ENTER(env, that, SetMenu_FUNC); rc = (jboolean)SetMenu((HWND)arg0, (HMENU)arg1); OS_NATIVE_EXIT(env, that, SetMenu_FUNC); return rc; }

Como puede verse, la implementación en Java del método SetMenu() de la clase

OS llama a un método del sistema operativo también llamado SetMenu(). (Tal como se adelantó, hay una relación uno a uno entre los métodos de SWT y los métodos gráficos de la plataforma.)

Cada plataforma con una implementación del SWT tiene una biblioteca compartida (en Windows, una biblioteca dinámica o DLL) y uno o más archivos JAR. La biblioteca compartida, específica de cada plataforma, resulta de compilar el código JNI-C que establece una correspondencia uno a uno entre los métodos Java y los métodos de la API gráfica propia del SO. En Windows, esta biblioteca contiene, entre otro mucho código, el código máquina resultante de compilar el código JNI-C del método setMenu() que se ha usado antes como ejemplo.

Los archivos JAR contienen las clases Java de SWT –Button, Tree, List, Text, Label, etc.–, que llaman a los métodos JNI-C correspondientes (los cuales, a su vez, llaman a los métodos nativos de la plataforma). Estas clases comunes, por tener las mismas declaraciones de sus métodos públicos para t odas las plataformas , permiten que el código Java que use SWT se ejecute sin necesidad de cambios en cualquier otra plataforma donde exista una implementación de SWT. En ese sentido, SWT resulta a la par transportable y específico de la plataforma, por contradictorio que parezca (en SWT, todas las interfaces directas a la API gráfica específica del SO están escritas en Java, excepto la de más bajo nivel). Tal y como dice IBM en su página web: “Un importante beneficio de usar SWT es que, una vez se desarrolla una interfaz de usuario en Linux, es también una interfaz de primera clase cuando se aplica a Windows. Lo inverso también es cierto”.

Un ejemplo completo aclarará el porqué del contradictorio carácter del SWT:

consideremos un widget SWT Button, subclase de la clase abstracta Control, y supongamos que trabajamos con implementaciones de SWT en Windows y Solaris (olvidemos temporalmente que hay más plataformas).

Page 11: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 11 de 114

En Windows, la clase Button tiene el siguiente código (por brevedad, omito todos los comentarios, salvo el de copyright, y algunos de los métodos): package org.eclipse.swt.widgets; /* * Copyright (c) 2000, 2002 IBM Corp. All rights reserved. * This file is made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html */ import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.win32.*; import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.events.*; public class Button extends Control { Image image; static final int ButtonProc; static final TCHAR ButtonClass = new TCHAR (0,"BUTTON", true ); static final int CheckWidth, CheckHeight; static { int hBitmap = OS.LoadBitmap (0, OS.OBM_CHECKBOXES); if (hBitmap == 0) { CheckWidth = OS.GetSystemMetrics (OS.IsWinCE ? OS.SM_CXSMICON : OS.SM_CXVSCROLL); CheckHeight = OS.GetSystemMetrics (OS.IsWinCE ? OS.SM_CYSMICON : OS.SM_CYVSCROLL); } else { BITMAP bitmap = new BITMAP (); OS.GetObject (hBitmap, BITMAP.sizeof, bitmap); OS.DeleteObject (hBitmap); CheckWidth = bitmap.bmWidth / 4; CheckHeight = bitmap.bmHeight / 3; } WNDCLASS lpWndClass = new WNDCLASS (); OS.GetClassInfo (0, ButtonClass, lpWndClass); ButtonProc = lpWndClass.lpfnWndProc; } public Button (Composite parent, int style) { super (parent, checkStyle (style)); } public void addSelectionListener (SelectionListener listener) { checkWidget (); if (listener == null ) error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener (listener); addListener (SWT.Selection,typedListener); addListener (SWT.DefaultSelection,typedListener); }

Page 12: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 12 de 114

int callWindowProc (int msg, int wParam, int lParam) { if (handle == 0) return 0; return OS.CallWindowProc (ButtonProc, handle, msg, wParam, lParam); } void click () { OS.SendMessage (handle, OS.BM_CLICK, 0, 0); } public Point computeSize (int wHint, int hHint, boolean changed) { checkWidget (); int border = getBorderWidth (); int width = border * 2, height = border * 2; if ((style & SWT.ARROW) != 0) { if ((style & (SWT.UP | SWT.DOWN)) != 0) { width += OS.GetSystemMetrics (OS.SM_CXVSCROLL); height += OS.GetSystemMetrics (OS.SM_CYVSCROLL); } else { width += OS.GetSystemMetrics (OS.SM_CXHSCROLL); height += OS.GetSystemMetrics (OS.SM_CYHSCROLL); } if (wHint != SWT.DEFAULT) width = wHint + (border * 2); if (hHint != SWT.DEFAULT) height = hHint + (border * 2); return new Point (width, height); } int extra = 0; int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); if ((bits & (OS.BS_BITMAP | OS.BS_ICON)) == 0) { int oldFont = 0; int hDC = OS.GetDC (handle); int newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); TEXTMETRIC lptm = new TEXTMETRIC (); OS.GetTextMetrics (hDC, lptm); int length = OS.GetWindowTextLength (handle); if (length == 0) { height += lptm.tmHeight; } else { extra = Math.max (8, lptm.tmAveCharWidth); TCHAR buffer = new TCHAR (getCodePage (), length + 1); OS.GetWindowText (handle, buffer, buffer.length ()); RECT rect = new RECT (); int flags = OS.DT_CALCRECT | OS.DT_SINGLELINE; OS.DrawText (hDC, buffer, length, rect, flags); width += rect.right - rect.left; height += rect.bottom - rect.top; } if (newFont != 0) OS.SelectObject (hDC, oldFont); OS.ReleaseDC (handle, hDC); } else { if (image != null ) { Rectangle rect = image.getBounds (); width = rect.width; height = rect.height; extra = 8; } }

Page 13: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 13 de 114

if ((style & (SWT.CHECK | SWT.RADIO)) != 0) { width += CheckWidth + extra; height = Math.max (height, CheckHeight + 3); } if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) { width += 10; height += 7; } if (wHint != SWT.DEFAULT) width = wHint + (border * 2); if (hHint != SWT.DEFAULT) height = hHint + (border * 2); return new Point (width, height); } int defaultBackground () { if ((style & (SWT.PUSH | SWT.TOGGLE)) != 0) { return OS.GetSysColor (OS.COLOR_BTNFACE); } return super .defaultBackground (); } int defaultForeground () { return OS.GetSysColor (OS.COLOR_BTNTEXT); } public int getAlignment () { checkWidget (); if ((style & SWT.ARROW) != 0) { if ((style & SWT.UP) != 0) return SWT.UP; if ((style & SWT.DOWN) != 0) return SWT.DOWN; if ((style & SWT.LEFT) != 0) return SWT.LEFT; if ((style & SWT.RIGHT) != 0) return SWT.RIGHT; return SWT.UP; } if ((style & SWT.LEFT) != 0) return SWT.LEFT; if ((style & SWT.CENTER) != 0) return SWT.CENTER; if ((style & SWT.RIGHT) != 0) return SWT.RIGHT; return SWT.LEFT; } String getNameText () { return getText (); } public String getText () { checkWidget (); int length = OS.GetWindowTextLength (handle); if (length == 0) return ""; TCHAR buffer = new TCHAR (getCodePage (), length + 1); OS.GetWindowText (handle, buffer, length + 1); return buffer.toString (0, length); } public void setText (String string) { checkWidget (); if (string == null ) error (SWT.ERROR_NULL_ARGUMENT); int newBits = OS.GetWindowLong (handle, OS.GWL_STYLE); int oldBits = newBits; newBits &= ~(OS.BS_BITMAP | OS.BS_ICON);

Page 14: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 14 de 114

if (newBits != oldBits) { OS.SetWindowLong (handle, OS.GWL_STYLE, newBits); } TCHAR buffer = new TCHAR (getCodePage (), string, true ); OS.SetWindowText (handle, buffer); } LRESULT WM_GETDLGCODE (int wParam, int lParam) { LRESULT result = super .WM_GETDLGCODE (wParam, lParam); if (result != null ) return result; if ((style & SWT.ARROW) != 0) { return new LRESULT (OS.DLGC_STATIC); } return result; } LRESULT WM_KILLFOCUS (int wParam, int lParam) { LRESULT result = super .WM_KILLFOCUS (wParam, lParam); if ((style & SWT.PUSH) != 0 && getDefault ()) { menuShell ().setDefaultButton (null , false ); } return result; } }

En Solaris 8, la clase Button presenta este código (por brevedad, omito todos los

comentarios, salvo el de copyright, y algunos de los métodos):

/******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.widgets; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.motif.*; import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.events.*; public class Button extends Control { String text = ""; Image image, bitmap, disabled; static final byte [] ARM_AND_ACTIVATE; static {

Page 15: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 15 de 114

String name = "ArmAndActivate"; int length = name.length(); char [] unicode = new char [length]; name.getChars (0, length, unicode, 0); byte [] buffer = new byte [length + 1]; for (int i = 0; i < length; i++) { buffer[i] = (byte ) unicode[i]; } ARM_AND_ACTIVATE = buffer; } public Button (Composite parent, int style) { super (parent, checkStyle (style)); } public void addSelectionListener(SelectionListener listener) { checkWidget(); if (listener == null ) error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener(listener); addListener(SWT.Selection,typedListener); addListener(SWT.DefaultSelection,typedListener); } public Point computeSize (int wHint, int hHint, boolean changed) { checkWidget(); int border = getBorderWidth (); int width = border * 2, height = border * 2; if ((style & SWT.ARROW) != 0) { width += display.scrolledMarginX; height += display.scrolledMarginY; if (wHint != SWT.DEFAULT) width = wHint + (border * 2); if (hHint != SWT.DEFAULT) height = hHint + (border * 2); return new Point (width, height); } XtWidgetGeometry result = new XtWidgetGeometry (); result.request_mode = OS.CWWidth | OS.CWHeight; int [] argList2 = {OS.XmNrecomputeSize, 1}; OS.XtSetValues(handle, argList2, argList2.length / 2); OS.XtQueryGeometry (handle, null , result); int [] argList3 = {OS.XmNrecomputeSize, 0}; OS.XtSetValues(handle, argList3, argList3.length / 2); width += result.width; height += result.height; int [] argList = {OS.XmNlabelType, 0}; OS.XtGetValues (handle, argList, argList.length / 2); if (argList [1] == OS.XmSTRING) { int [] argList1 = {OS.XmNlabelString, 0}; OS.XtGetValues (handle, argList1, argList1.length / 2); int xmString = argList1 [1]; if (OS.XmStringEmpty (xmString)) height += getFontHeight (font.handle); if (xmString != 0) OS.XmStringFree (xmString); } if (wHint != SWT.DEFAULT || hHint != SWT.DEFAULT) { int [] argList4 = new int [] {OS.XmNmarginLeft, 0, OS.XmNmarginRight, 0, OS.XmNmarginTop, 0, OS.XmNmarginBottom, 0}; OS.XtGetValues (handle, argList4, argList4.length / 2); if (wHint != SWT.DEFAULT) width = wHint + argList4 [1] + argList4 [3] + (border * 2);

Page 16: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 16 de 114

if (hHint != SWT.DEFAULT) height = hHint + argList4 [5] + argList4 [7] + (border * 2); } return new Point (width, height); } public int getAlignment () { checkWidget(); if ((style & SWT.ARROW) != 0) { int [] argList = {OS.XmNarrowDirection, 0}; OS.XtGetValues (handle, argList, argList.length / 2); int direction = argList [1]; if (direction == OS.XmARROW_UP) return SWT.UP; if (direction == OS.XmARROW_DOWN) return SWT.DOWN; if (direction == OS.XmARROW_LEFT) return SWT.LEFT; if (direction == OS.XmARROW_RIGHT) return SWT.RIGHT; return SWT.UP; } int [] argList = {OS.XmNalignment, 0}; OS.XtGetValues (handle, argList, argList.length / 2); int alignment = argList [1]; if (alignment == OS.XmALIGNMENT_BEGINNING) return SWT.LEFT; if (alignment == OS.XmALIGNMENT_CENTER) return SWT.CENTER; if (alignment == OS.XmALIGNMENT_END)return SWT.RIGHT; return SWT.CENTER; } boolean getDefault () { if ((style & SWT.PUSH) == 0) return false ; return this == menuShell ().defaultButton; } String getNameText () { return getText (); } public String getText () { checkWidget(); if ((style & SWT.ARROW) != 0) return ""; return text; } public void setAlignment (int alignment) { checkWidget(); if ((style & SWT.ARROW) != 0) { int [] argList = {OS.XmNarrowDirection, OS.XmARROW_UP}; if ((alignment & SWT.UP) != 0) argList [1] = OS.XmARROW_UP; if ((alignment & SWT.DOWN) != 0) argList [1] = OS.XmARROW_DOWN; if ((alignment & SWT.LEFT) != 0) argList [1] = OS.XmARROW_LEFT; if ((alignment & SWT.RIGHT) != 0) argList [1] = OS.XmARROW_RIGHT; OS.XtSetValues (handle, argList, argList.length / 2); return ; } if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) return ; int [] argList = {OS.XmNalignment, OS.XmALIGNMENT_BEGINNING}; if ((alignment & SWT.CENTER) != 0) argList [1] = OS.XmALIGNMENT_CENTER; if ((alignment & SWT.RIGHT) != 0) argList [1] = OS.XmALIGNMENT_END; OS.XtSetValues (handle, argList, argList.length / 2); }

Page 17: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 17 de 114

public void setText (String string) { checkWidget(); if (string == null ) error (SWT.ERROR_NULL_ARGUMENT); if ((style & SWT.ARROW) != 0) return ; text = string; char [] text = new char [string.length ()]; string.getChars (0, text.length, text, 0); int mnemonic = fixMnemonic (text); byte [] buffer = Converter.wcsToMbcs (getCodePage (), text, true ); int xmString = OS.XmStringParseText ( buffer, 0, OS.XmFONTLIST_DEFAULT_TAG, OS.XmCHARSET_TEXT, null , 0, 0); if (xmString == 0) error (SWT.ERROR_CANNOT_SET_TEXT); if (mnemonic == 0) mnemonic = OS.XK_VoidSymbol; int [] argList = { OS.XmNlabelType, OS.XmSTRING, OS.XmNlabelString, xmString, OS.XmNmnemonic, mnemonic, }; OS.XtSetValues (handle, argList, argList.length / 2); if (xmString != 0) OS.XmStringFree (xmString); } int xFocusIn (XFocusChangeEvent xEvent) { super .xFocusIn (xEvent); if (handle == 0) return 0; if ((style & SWT.PUSH) != 0) { menuShell ().setDefaultButton (this , false ); } return 0; } }

Como puede observarse, la clase Button en Solaris presenta un código muy distinto

del correspondiente a la misma clase en Windows, pero ambas mantienen la misma declaración –es decir, los mismos argumentos y el mismo tipo de retorno– para todos los métodos públicos. Por ejemplo, el método público setText() de Button mantiene la misma declaración tanto en Solaris como en Windows: public void setText (String string). (Lo mismo sucede en todas las demás plataformas para las que está disponible SWT.)

En cuanto a la implementación de los métodos públicos, varía completamente de una a otra cada plataforma. En el caso de setText(), se usan en Windows llamadas a métodos como OS.GetWindowLong(), que llama, a su vez, al método GetWindowLong() de la biblioteca gráfica Win32; en Solaris se usan llamadas a métodos como OS.XmStringParseText(), que llama, a su vez, al método XmStringParseText() de la bibliotecas gráfica Motif. Tal como se dijo antes, la clase OS representa el sistema operativo de la plataforma.

Page 18: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 18 de 114

Los métodos que no son públicos gozan de completa libertad en cuanto a declaración. Generalmente, no tienen por qué existir en todas las plataformas. Por ejemplo, no hay un método con una declaración int callWindowProc(int p0, int p1, int p2) en la clase Button de Solaris, método que goza de buena salud en Windows.

Como ya se adelantó hace unas páginas, que los métodos públicos de los widgets SWT se declaren igual en todas las plataformas causa que el SWT sea transportable. En el ejemplo de Button, la implementación de cada método en Solaris no será transportable a Windows, y viceversa; pero el código Java que utilice los métodos públicos de Button sí lo será, puesto que ambas plataformas tienen implementaciones del SWT.

Continuando con el ejemplo de setText(), la sentencia miBoton.setText("Soy un botón SWT") hará llamadas en Windows y Solaris, a través de JNI, a métodos nativos completamente diferentes; pero funcionará en ambas plataformas (dando distintas resultados gráficos, claro está). El código Java que llama a SWT no necesita conocer la implementación de las clases SWT ni el código JNI-C encargado de llamar a la API gráfica correspondiente. Más aún: si lo hiciera se incumpliría el principio de encapsulado, fundamental en la programación orientada a objetos.

Las bibliotecas JNI-SWT deben compilarse para cada plataforma, lo cual crea un archivo con extensión .dll en Windows y otro con extensión .so en Solaris. En la página web de Eclipse se puede descargar el código JNI-C de la biblioteca JNI-SWT para cada plataforma, así como el código compilado para cada plataforma. Un programa que utilice SWT empleará las bibliotecas Win32 o MFC (propias de Windows) cuando se ejecuta en Windows (98/ME/2000/XP), y las bibliotecas de Motif cuando se ejecuta en Solaris.

La correspondencia casi exacta entre los objetos gráficos de SWT –widgets, tipos de letra, colores, imágenes– y los del sistema operativo hace que el recolector de basura de Java no sirva para liberar los recursos asociados a esos objetos; pues la tarea natural del recolector es liberar los recursos asociados a objetos que “viven” en la máquina virtual de Java y que ya no se utilizan, no liberar recursos del sistema operativo donde se ejecuta la MVJ. Por esto, la liberación de los recursos asociados a objetos SWT debe establecerla el programador. Por ejemplo, una ventana repleta de controles puede cerrarse de varias maneras –uso “cerrar” en el sentido de hacerla desaparecer de la vista del usuario–; pero el programador deberá llamar explícitamente al método dispose() del display correspondiente si realmente quiere liberar los recursos de la ventana y de sus controles. En caso contrario, puede suceder que la aplicación se cuelgue o funcione muy lentamente si contiene muchas ventanas que ya no se necesitan y cuyos recursos no se han liberado. Para evitar fallos de memoria y la disminución del rendimiento, se recomienda liberar los recursos asociados a un objeto SWT en cuanto se deje de necesitarlo.

SWT sigue la estrategia de que liberar los recursos de un control “padre” conlleva la liberación de los recursos de todos los controles “hijos”. Dicho de otro modo: al llamar al método dispose() del padre, se llama a cada método dispose() de los hijos.

Métodos como dispose() resultan necesarios cuando se trabaja con componentes gráficos o con sockets, pues llaman a métodos nativos que saben cómo liberar los recursos asociados del sistema operativo. Si desea más información sobre el uso de dispose() con sockets, puede consultar el apartado 3.3 del tutorial java.net y java.nio. Cómo hacer un chat en Java , http://www.javahispano.org/tutorials.item.action?id=7). Esas llamadas a métodos nativos son inevitables, ya que los componentes gráficos de peso pesado y las conexiones de red dependen por completo del SO.

Page 19: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 19 de 114

En el caso de los objetos SWT correspondientes a colores (Color), imágenes (Image) y tipos de letra (Font), el programador debe ser cuidadoso. De un lado, dichos objetos carecen de objetos “padre”. De otro, los recursos que consumen no se liberan cuando se llama al método dispose() de los componentes donde se usan tales objetos.

Estas dos características no se deben a ningún error de diseño. Antes al contrario: responden a un entendimiento cabal de la naturaleza de esos objetos. Si, por ejemplo, las imágenes tuvieran que crearse asociadas a componentes padre (ventanas, botones, listas, menús...), todos los componentes con una misma imagen necesitarían sendas instancias de la clase Image. Esta situación sería muy incómoda para el programador (quien tendría que escribir la instaciación una y otra vez) y para el sistema operativo (imaginémoslo como un gruñón que se preguntara por qué demonios le obligan a mantener tantos objetos Image, cuando en realidad corresponden a un misma imagen, y que amenazara con colgar el sistema como protesta). A consecuencia de la “libertad” de la que gozan esos objetos, resulta obligatorio que no se destruyan cuando se destruyen los componentes que los usan. Si varios componentes usaran un mismo objeto Image y al destruir uno se destruyera el objeto Image, ¿en qué estado se encontrarían los restantes componentes? Sin imagen, que ya estaría en el cubo de la basura.

Como los objetos Color, Image y Font no se destruyen cuando desaparecen los componentes que los usan, el programador debe liberarlos explícitamente llamando a dispose(). En el apartado dedicado a JFace veremos cómo se puede simplificar la liberación de los recursos que consumen estos objetos.

Toda la interfaz gráfica de Eclipse se basa en SWT. Ahora bien, ello no significa que

este componente gráfico se pueda usar sólo con Eclipse: las bibliotecas SWT se pueden descargar independientemente de Eclipse y pueden usarse para construir aplicaciones independientes. En la última versión de Eclipse (3.0.2), lanzada el 11 de marzo de 2005 (la versión 3.1M5a, aún no definitiva, salió en febrero de este año), los componentes SWT y JFace se hallan disponibles para las siguientes plataformas:

� Windows 98/ME/2000/XP

� Windows PocketPC 2002 (Strong ARM)

� Linux (x86/Motif)

� Linux (x86/GTK 2)

� Linux (AMD 64/GTK 2)

� Linux (IA 64/GTK 2)

� Solaris 8 (SPARC/Motif)

� AIX (PPC/Motif)

� HP-UX (HP9000/Motif)

� HP-UX (IA 64/Motif) Como la licencia de SWT coincide con la de Eclipse (Common Public License, ya

explicada en el primer artículo de esta serie: http://www.javahispano.org/articles.article.action?id=75), cualquier programador puede usar este componente sin pagar regalías. Para ello, debe configurar el CLASSPATH de su aplicación para que incluya el archivo jar del SWT (dependiendo de la plataforma, pueden ser varios) y la propiedad java.library.path para que incluya la biblioteca compartida JNI-SWT propia de la plataforma usada (esta biblioteca resulta de compilar

Page 20: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 20 de 114

todo el código JNI-C que usan las clases SWT; en Windows tiene un nombre del tipo swt-win32.xxxx.dll).

En las siguientes figuras se muestra el aspecto de Eclipse en varias plataformas.

Como Eclipse usa exclusivamente componentes SWT, su aspecto cambia en cada plataforma.

Fig. 16. SWT en acción: Eclipse en Linux-Motif. Ext raído de la documentación

oficial de Eclipse.

Page 21: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 21 de 114

Fig. 17. SWT en acción: Eclipse en Linux/Gnome2

Page 22: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 22 de 114

Fig. 18. SWT en acción: Eclipse en Windows XP

Page 23: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 23 de 114

Fig. 19. SWT en acción: Eclipse en Mac OS X

Page 24: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 24 de 114

15. Ejemplos de uso del Standard Widget Tool (SWT)

Esta sección no pretende, ni mucho menos, ser una introducción completa a SWT. Sus objetivos son mucho más modestos: explicar qué se necesita para programar con este componente gráfico, presentar algunos aspectos de su uso y dar unos cuantos ejemplos representativos de cómo se usan los widgets SWT. Dar una explicación completa del funcionamiento de SWT queda fuera de las metas de esta serie de artículos (definidas en el primero, http://www.javahispano.org/articles.article.action?id=75).

Usando SWT, el típico programa HolaMundo quedaría así:

import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; public class Saludos { public static void main(String args[]){ // Se crea un display que servirá como contenedor para el shell. Display display = new Display(); // Se coloca el display dentro del shell. Shell shell = new Shell(display); // Se establece el tamaño y el texto del shell. shell.setSize(250, 120); shell.setText("Mi primera aplicación con SWT"); // Se crea una etiqueta centrada en la ventana y se le da un texto. Label etiqueta= new Label(shell, SWT.CENTER); etiqueta.setText("Saludos a los lectores de javaHispano"); etiqueta.setBounds(shell.getClientArea()); // Se muestra el shell; un shell es invisible salvo que se llame a open(). shell.open (); // Se entra en un bucle para leer y enviar los sucesos del usuario. // Si no hay ningún suceso que tratar, el método sleep() hace que el // programa espere el suceso siguiente sin consumir ciclos de CPU. // Se sale del bucle cuando el usuario cierra el shell. while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } // Se cierra el display y se liberan los recursos que empleaba del sistema operativo // Siempre es conveniente liberar explícitamente los recursos // que no se van a necesitar. En este caso no es necesario llamar a dispose(), // pues si se llega a aquí es porque el programa va a terminar, lo que implica que // se liberarán los recursos asociados; pero es una buena práctica acostumbrarse // a hacerlo.

Ejemplo 1: Saludos.java

Page 25: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 25 de 114

display.dispose (); } }

Para que un programa con SWT pueda compilarse y ejecutarse en el entorno de Eclipse, se necesitan dos pasos previos.

El primero consiste en indicar al compilador dónde está el código Java de SWT; es

decir, dónde se encuentran las clases SWT. Éstas se almacenan en el archivo swt.jar. Para indicar a Eclipse dónde debe buscar el archivo swt.jar hay que seguir varios pasos. En primer lugar, hay que apretar, sobre el nombre del proyecto de Java, el botón derecho del ratón (véase la figura 20). A continuación, hay que seleccionar la opción Properties . En la ventana que aparece debe seleccionarse Java Build Path (panel de la derecha) y la pestaña Libraries (véase la figura 21). Acto seguido, debe incluirse swt.jar con el botón Add External JARs... (véase la figura 22).

Según el FAQ más actualizado de Eclipse (http://www.eclipse.org/eclipse/faq/eclipse-faq.html), swt.jar se encuentra –dependiendo de la plataforma– en

• win32: INSTALLDIR\eclipse\plugins\org.eclipse.swt.win32_3.0.1\ws\win32\

• Linux GTK: INSTALLDIR/eclipse/plugins/org.eclipse.swt.gtk_3.0.1/ws/gtk/

• Linux Motif: INSTALLDIR/eclipse/plugins/org.eclipse.swt.motif_3.0.1/ws/motif/

• Photon QNX: INSTALLDIR/eclipse/plugins/org.eclipse.swt.photon_3.0.1/ws/photon/

• Mac OS X: INSTALLDIR/eclipse/plugins/org.eclipse.swt.carbon_3.0.1/ws/carbon/ INSTALLDIR es el directorio donde se ha instalado Eclipse. Dependiendo de la

versión de SWT que se use, cambiará el número separado por puntos que aparece en las rutas (en vez de 3.0.1, podría ser 3.1.0, por ejemplo).

Page 26: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 26 de 114

Figura 20. Nótese que la vista que se usa es la de paquetes

Page 27: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 27 de 114

Figura 21. Hay que apretar el botón Add External JA Rs...

Figura 22. Hay que seleccionar el archivo swt.jar ( en otra plataforma, se encontrará

en otro directorio)

Page 28: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 28 de 114

El segundo paso que se requiere para ejecutar el programa consiste en indicar a Eclipse dónde está la biblioteca compartida que requiere swt.jar. Una manera consiste en introducir, cuando se arranca la máquina virtual de Java, la ubicación de la biblioteca compartida como argumento de ejecución. Para ello, basta elegir el menú Run , escoger Run... (véase la figura 23), elegir la pestaña Arguments en la parte derecha de la pantalla e introducir en el área de texto VM arguments lo siguiente (véase la figura 24a):

-Djava.library.path=<directorio que contiene la biblioteca compartida para SWT> Tal y como sucedía con swt.jar, la biblioteca se encontrará en una ubicación dependiente de la plataforma. Según el FAQ de Eclipse, las ubicaciones serán del estilo (la lista de plataformas no es exhaustiva): • Windows: INSTALLDIR\eclipse\plugins\org.eclipse.swt.win32_3.0.1\os\win32\x86

• Linux GTK: INSTALLDIR/eclipse/plugins/org.eclipse.swt.gtk_3.0.1/os/linux/x86

• Linux Motif: INSTALLDIR/eclipse/plugins/org.eclipse.swt.motif_3.0.1/os/linux/x86

• Photon QNX: INSTALLDIR/eclipse/plugins/org.eclipse.swt.photon_3.0.1/os/qnx/x86

• Mac OS X: INSTALLDIR/eclipse/plugins/org.eclipse.swt.carbon_3.0.1/os/macosx/ppc

Figura 23. Se escoge Run...

Page 29: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 29 de 114

Figura 24a. La versión de Eclipse de la captura de pantalla es la 3.1M4 El nombre exacto de la biblioteca JNI–SWT varía en cada versión de Eclipse (a

veces, también varía con la plataforma, aunque no varíe la versión). En la versión 3.1M3 de Eclipse para Windows 98/ME/2000/XP, el nombre de la biblioteca es swt-win-32-3111.dll (véase la figura 24b).

Figura 24b. Biblioteca JNI-SWT correspondiente a Ec lipse 3.1M3

Page 30: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 30 de 114

Completados todos los pasos anteriores, la ejecución de la clase Saludos en Windows XP producirá una ventana similar a la de la figura 25a.

Figura 25a. Resultado de ejecutar la clase Saludos

Figura 25b. Manteniendo en ejecución la clase Salud os, la ventana cambia de aspecto cuando se cambia el estilo de Windows XP po r el clásico de Windows.

Como ya se señaló en el apartado anterior, para desarrollar o ejecutar aplicaciones

SWT no se necesita el entorno de desarrollo Eclipse. Para ejecutar en Windows una aplicación SWT sin Eclipse, hay que añadir el archivo swt.jar al CLASSPATH e incluir la biblioteca dinámica swt-win-32-xxxx.dll en el java.library.path. Tanto swt.jar como la DLL se pueden descargar sin el resto de Eclipse.

Por ejemplo, en el caso de que ambos archivos estén en C:\SWT, la siguiente orden compilará la aplicación Saludos desde la línea de órdenes:

javac -classpath C:\SWT\swt.jar Saludos.java

La siguiente orden ejecutará Saludos desde la línea de órdenes:

java -classpath C:\SWT\swt.jar -Djava.library.path= C:\SWT Saludos Para el resto de las plataformas, el proceso resulta similar a éste.

Page 31: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 31 de 114

La clase Saludos, si bien muy simple, alberga la estructura de cualquier aplicación SWT:

1) Se crea un objeto Display.

2) Se crea un objeto Shell que sirve como ventana principal de la aplicación.

3) Se crean dentro del shell los widgets (componentes gráficos) que se deseen.

4) Se configuran los tamaños de los widgets (normalmente, en este paso se registran los sucesos a los cuales atenderán los widgets).

5) Se abre la ventana del shell.

6) Se entra en un bucle donde se comprueban los sucesos que se van produciendo.

7) Se cierra el objeto Display y se liberan los recursos asociados.

La clase Display (contenida en el paquete org.eclipse.swt.widgets ) actúa como “puente” entre el SWT y las operaciones del sistema de interfaz gráfica de la plataforma. Según la documentación de esta clase, su principal función es implementar el bucle de sucesos de SWT mediante el modelo de sucesos de la plataforma. Además, proporciona métodos para acceder a información sobre el sistema operativo y para controlar y gestionar los recursos del sistema donde se ejecuta SWT. En resumen, un objeto Display se comporta como un intermediario entre la interfaz de usuario y el componente o componentes que lo implementan en una plataforma.

Por lo general, el programador –salvo que escriba aplicaciones multihilo– debe preocuparse solamente de: a) crear un objeto Display antes de crear ninguna ventana; y b) cerrarlo cuando ya no se necesite.

El método dispose() se encarga de liberar los recursos que el display consumía del sistema de ventanas específico de la plataforma (memoria, punteros). Al llamarlo, se eliminan todos los shells que tenía el display.

Las instancias de la clase Shell (contenida en el paquete org.eclipse.swt.widgets )

vienen a ser ventanas gestionadas por el gestor de ventanas propio de la plataforma. Cuando el usuario mueve o cambia el tamaño de una ventana, SWT pasa el tratamiento de estas acciones a la API gráfica del SO. Esta clase tiene varios constructores que admiten como argumento un objeto shell: con ellos se pueden generan shells de diálogo o secundarios (shell significa cáscara).

El método dispose() de esta clase actúa de forma similar al método homónimo de la clase Display.

Nota: La manera más sencilla de evitar la configuración del CLASSPATH y del argumento -Djava.library.path desde la línea de órdenes es colocar el fichero o los ficheros JAR en el directorio lib/ext del JRE (Java Runtime Environment), y la biblioteca compartida JNI-SWT en el directorio bin del JRE.

Page 32: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 32 de 114

Si comparamos SWT con Swing, los componentes de Swing serían equivalentes a los widgets del SWT, y los marcos y ventanas (frames and windows), a los shells.

En el constructor de la etiqueta habrá visto que hay un segundo argumento en el

constructor:

Label etiqueta= new Label(shell, SWT.CENTER); SWT.CENTER (o CENTER, por abreviar) es un estilo . Los estilos son constantes

enteras que se emplean para establecer el aspecto y comportamiento de los widgets. En este ejemplo, el estilo CENTER indica que el texto de la etiqueta debe centrarse respecto a ella. Todos los estilos están definidos en la clase org.eclipse.swt.SWT . Una vez se asigna un estilo a un widget, aquél no puede cambiarse. La clase Shell que acabamos de ver admite los siguientes estilos: BORDER, H_SCROLL, V_SCROLL, CLOSE, MIN, MAX, RESIZE, TITLE, SHELL_TRIM y DIALOG_TRIM.

Un widget puede aceptar varios estilos:

Label etiqueta = new Label(shell, SWT.CENTER | SWT.HORIZONTAL | SWT.SEPARATOR);

Figura 26. Ejemplo de distintos estilos de un mensa je de diálogo El paquete org.eclipse.swt.widgets incluye un conjunto de widgets o componentes

SWT formado, entre otros, por estos elementos:

- Button. SWT no tiene una clase individual para un botón redondo, de flecha, etc.: todos son instancias de Button.

- Label. Una etiqueta muestra una cadena de texto, una imagen o una línea –vertical u horizontal– separadora.

- Text. Muestra un texto susceptible de ser editado, ya sea de una línea o de varias.

- Slider. Control que representa un intervalo de valores numéricos.

- ProgressBar. Control que indica el porcentaje cumplido de una tarea (descargar un archivo, cargar una aplicación, etc.).

Page 33: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 33 de 114

- Combo. Control que permite seleccionar un valor de una lista desplegable o introducir directamente el valor deseado.

- List. Control que permite seleccionar (de forma simple o múltiple) elementos de una lista de cadenas de texto.

- Composite. Control que permite agrupar otros controles. Equivaldría a un contenedor (container) de Swing.

- Group. Control formado a partir de un Composite con título y borde.

- Canvas. Control que permite operaciones gráficas de todo tipo (dibujar un octógono azul, por ejemplo)

- Menu. Control que contiene elementos seleccionables de tipo menú.

- MenuItem. Elemento seleccionable que representa un elemento en un menú.

- Table. Control seleccionable que muestra una lista de elementos de una tabla.

- TableColumn . Elemento seleccionable que representa una columna de una tabla.

- TableItem. Objeto seleccionable que representa un elemento de una tabla.

- ToolBar. Control compuesto que permite diseñar elementos de barras de herramientas.

- ToolItem. Objeto seleccionable que representa un elemento de una barra de herramientas.

- Tree. Control seleccionable en forma de árbol que muestra una lista jerárquica de elementos.

- TreeItem. Objeto que representa una jerarquía de objetos en un control Tree.

Page 34: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 34 de 114

Figura 27. Funcionamiento interno de SWT

Antes de dar algunos ejemplos del uso de estos componentes, creo pertinente incluir aquí algunos comentarios sobre el tratamiento de sucesos en SWT. El tratamiento de los sucesos en el SWT resulta muy similar al de Swing y al de AWT: a cada widget se le añade una clase Listener mediante un método del estilo addXXXListener(), cuyo argumento es la clase que implementa la correspondiente interfaz de tipo Listener. Asimismo, existen clases adaptadoras –clases que implementan por omisión las interfaces Listener–, de manera que el programador necesite escribir sólo el código de los sucesos que verdaderamente le interesan.

Plataforma

Display Shell

Composite

Widget

Widget

Widget

Widget

Bibliotecas

gráficas

JNI

FUNCIONAMIENTO INTERNO DEL COMPONENTE SWT

Miguel Ángel Abián, 2005

Page 35: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 35 de 114

Nota: Si no tiene experiencia con el tratamiento de sucesos en Swing o AWT, le resultará útil saber lo siguiente:

1) Cada suceso se asocia con una acción del usuario (pulsar una tecla, mover el ratón...).

2) Cada suceso tiene asociado una interfaz de Java llamada Listener (oyente).

3) Es tarea del programador crear una clase Listener que implemente la interfaz Listener correspondiente y en la que se especifique qué respuesta debe darse cuando se produzca un suceso.

4) Para añadir una clase Listener a un control se usan métodos del estilo addXXXListener().

5) Las clases Adapters (adaptadoras) son clases que implementan las interfaces Listener con una implementación por omisión para cada método. En vez de una clase Listener, el programador puede asociar un Adapter a un componente, de manera que sólo tenga que implementar los métodos que necesite. Por ejemplo, a la interfaz FocusListener le corresponde la clase adaptadora FocusAdapter.

Page 36: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 36 de 114

Figura 28. Tabla con los sucesos y las clases Liste ner más importantes

Page 37: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 37 de 114

He aquí un ejemplo de código para tratar sucesos (corresponde a un componente

SWT de tipo Button):

import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.events.*; /** * Esta clase genera un botón que inicialmente permanece apretado. * * La clase Button admite los siguientes estilos: BORDER, CHECK, PUSH, * RADIO, TOGGLE, FLAT, ARROW (con UP, DOWN), LEFT, RIGHT y CENTER. * * BORDER crea un botón con borde. * CHECK crea un botón de casilla de verificación. * PUSH crea un botón estándar (valor por omisión). * RADIO crea un botón de opción. * TOGGLE crea un botón que mantiene su estado pulsado o no pulsado. * FLAT crea un botón sin efectos de relieve 3D (plano). * ARROW crea un botón en forma de flecha (UP y DOWN marcan el sentido de ésta). * LEFT, RIGHT, CENTER alinean el texto asociado al botón. */ public class EjemploBoton { public static void main(String args[]) { // Se crea un display que servirá como contenedor para el shell. Display display = new Display(); // Se coloca el display dentro del shell. Shell shell = new Shell(display); // Se establece el tamaño y el texto del shell. shell.setSize(250, 120); shell.setText("Ventana hecha con el SWT"); // Se establece el tipo, eltamaño y el texto del botón. // Un botón TOGGLE permanece presionado tras pulsarlo, hasta que se vuelve a // pulsar. Button boton = new Button(shell, SWT.TOGGLE); boton.setSize(150, 50); boton.setText("Soy un botón de tipo TOGGLE"); // Tratamiento de sucesos: muy similar a como se hace en Swing. // Nótese que hay que implementar todos los métodos de cada interfaz // Listener. boton.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { System.out.println("Se ha seleccionado el botón"); } public void widgetDefaultSelected(SelectionEvent e) { System.out.println("Se ha seleccionado el botón");

Ejemplo 2: EjemploBoton.java

Page 38: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 38 de 114

} }); boton.addMouseListener(new MouseListener() { public void mouseDown(MouseEvent e) { System.out.println("Se ha movido el ratón hacia abajo"); } public void mouseUp(MouseEvent e) { System.out.println("Se ha movido el ratón hacia arriba"); } public void mouseDoubleClick(MouseEvent e) { System.out.println("Se ha hecho doble click en el botón"); } }); // Se muestra el shell; un shell es invisible salvo que se llame a open(). shell.open(); // Se entra en un bucle para leer y enviar los sucesos del usuario. while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } // Se cierra el display y se liberan los recursos del sistema operativo // asociados. display.dispose(); } }

Figura 29. Resultado de ejecutar la clase EjemploBo ton

Page 39: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 39 de 114

Si en la clase EjemploBoton interesara procesar sólo el suceso Selection, sería

mucho más rápido usar la correspondiente clase adaptadora:

// Tratamiento del suceso Selection con adaptadores. boton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { System.out.println("Se ha seleccionado el botón"); } });

El ejemplo anterior quedaría así:

import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.events.*; public class EjemploBoton2 { public static void main(String args[]){ // Se crea un display que servirá como contenedor para el shell. Display display = new Display(); // Se coloca el display dentro del shell. Shell shell = new Shell(display); // Se establece el tamaño y el texto del shell. shell.setSize(250, 120); shell.setText("Ventana hecha con el SWT"); // Se establece el tipo, el tamaño y el texto del botón. Button boton = new Button(shell, SWT.TOGGLE); boton.setSize(150, 50); boton.setText("Soy un botón de tipo TOGGLE"); // Tratamiento del suceso Selection con adaptadores. boton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { System.out.println("Se ha seleccionado el botón"); } }); shell.open (); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose (); }

Ejemplo 3: EjemploBoton2.java

Page 40: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 40 de 114

}

Con todo, existe una relevante diferencia entre el SWT y Swing: un programa que

use SWT y no disponga de algún bucle que se encargue de leer y procesar los sucesos del sistema operativo terminará en cuanto se llegue al final del método main(). Por ejemplo, el usuario sólo verá una ventana que se cierra al momento si ejecuta las clases anteriores sin este código (si su máquina es lo bastante rápida, puede que ni siquiera llegue a ver la ventana):

while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } }

Asociada a esta diferencia entre SWT y Swing, está el hecho de que los sucesos de

SWT sólo se entregan al programa (y, en consecuencia, sólo pueden procesarse) cuando se llama a un método SWT. En los ejemplos anteriores, el método readAndDispatch() se encarga de entregar al programa en ejecución los sucesos generados por el usuario. Sin él, el comportamiento del botón sería anómalo: no respondería a las acciones del usuario (defecto, dicho sea de paso, que los usuarios desprecian).

A continuación, incluyo unos cuantos ejemplos de uso de los principales controles

SWT. Cuando se especifican coordenadas, hay que tener en cuenta que (0, 0) corresponde a la esquina superior izquierda, que los puntos situados por debajo del origen tienen su componente y positiva y que los puntos a la derecha del origen tiene su componente x positiva.

import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.*; /** * Esta clase genera una ventana con una imagen y una barra de menús * Se necesita incluir el paquete org.eclips.swt.graphics.Image * para poder trabajar con imágenes en SWT. * * La clase Menu actúa como un contenedor para los objetos MenuItem. * La clase Menu admite los siguientes estilos: BAR, DROP_DOWN y POP_UP. * * BAR crea una barra de menús. * DROP_DOWN crea un menú desplegable. * POP_UP crea un menú contextual. * * * La clase MenuItem admite los siguientes estilos: CHECK, CASCADE, PUSH, RADIO y

Ejemplo 4: EjemploMenu1.java

Page 41: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 41 de 114

* SEPARATOR. * * CHECK crea un menú de casilla de verificación. * CASCADE crea un menú en cascada con un submenú. * PUSH crea un elemento estándar de menú. * RADIO crea un menú de opción. * SEPARATOR crea un separador de elementos de menú. * */ public class EjemploMenu1{ public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(200, 200); shell.setText("Ejemplo 1 de menús"); shell.setImage(new Image(display,"c:\\eclipse.jpg")); Menu menu = new Menu(shell, SWT.BAR); shell.setMenuBar(menu); shell.open(); while (!shell.isDisposed()){ if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }

Figura 30. Resultado de ejecutar la clase EjemploMe nu1

Page 42: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 42 de 114

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.Image; /** * Esta clase genera una ventana una barra de menús que tiene dos menús con submenús. * Se necesita incluir el paquete org.eclips.swt.graphics.Image * para poder trabajar con imágenes en SWT. * */ public class EjemploMenu2 { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 300); shell.setText("Ejemplo 2 de menús"); shell.setImage(new Image(display, "c:\\Eclipse.jpg")); // Se crea la barra de menús. Se pueden crear más, pero sólo una // puede ser visible en un instante dado. Menu barra = new Menu(shell, SWT.BAR); // Se crea un MenuItem llamado archivo. MenuItem archivo = new MenuItem(barra, SWT.CASCADE); archivo.setText("Archivo"); // Se crea el menú de archivos y se asocia al MenuItem archivo de la barra // de menús. Menu menuArchivo = new Menu(shell, SWT.DROP_DOWN); archivo.setMenu(menuArchivo); MenuItem abrir = new MenuItem(menuArchivo, SWT.RADIO); abrir.setText("Abrir"); // Se añade al menú de archivos una línea separadora. MenuItem separador = new MenuItem(menuArchivo, SWT.SEPARATOR); // Se añade al menú Archivo un elemento Salir. MenuItem salir = new MenuItem(menuArchivo, SWT.PUSH); salir.setText("Salir"); // Se crea un MenuItem llamado editar. MenuItem editar = new MenuItem(barra, SWT.CASCADE); editar.setText("Edición");

Ejemplo 5: EjemploMenu2.java

Page 43: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 43 de 114

// Se crea el menú de edición y se asocia al MenuItem editar de la barra de // menús. Menu menuEditar = new Menu(shell, SWT.DROP_DOWN); editar.setMenu(menuEditar); MenuItem cortar = new MenuItem(menuEditar, SWT.PUSH); cortar.setText("Cortar"); // Se añade al menú de edición un elemento Copiar. MenuItem copiar = new MenuItem(menuEditar, SWT.PUSH); copiar.setText("Copiar"); // Se añade al menú de edición un elemento Pegar. MenuItem pegar = new MenuItem(menuEditar, SWT.PUSH); pegar.setText("Pegar"); // Tratamiento de los sucesos del usuario. Es obligatorio // incluir el método widgetDefaultSelected, aunque esté // vacío. abrir.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { System.out.println("Apretó Abrir"); } public void widgetDefaultSelected(SelectionEvent e) { } }); salir.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { System.exit(0); // se sale de la aplicación } public void widgetDefaultSelected(SelectionEvent e) { } }); cortar.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { System.out.println("Apretó Cortar"); } public void widgetDefaultSelected(SelectionEvent e) { } }); copiar.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { System.out.println("Apretó Copiar"); } public void widgetDefaultSelected(SelectionEvent e) { } }); pegar.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { System.out.println("Apretó Pegar"); } public void widgetDefaultSelected(SelectionEvent e) { } }); shell.setMenuBar(barra); shell.open();

Page 44: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 44 de 114

while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }

Figura 31. Resultado de ejecutar la clase EjemploMe nu2

Page 45: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 45 de 114

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.events.*; import org.eclipse.swt.layout.*; /** * Esta clase genera un cuadro de texto multilínea. * Se necesita incluir el paquete org.eclips.swt.graphics.Image * para poder trabajar con imágenes en SWT. * * La clase Label admite los siguientes estilos: BORDER, CENTER, * LEFT, RIGHT, WRAP y SEPARATOR (con HORIZONTAL, SHADOW_IN, * SHADOW_OUT, SHADOW_NONE y VERTICAL). * * BORDER crea una etiqueta con borde. * CENTER, LEFT y RIGHT alinean el texto de la etiqueta con respecto a la etiqueta. * WRAP hace que el texto dentro de la etiqueta se pueda dividir en varias líneas, si * resulta necesario. * SHADOW_IN (usado con SEPARATOR) crea un separador que parece empotrado * en la ventana. * SHADOW_OUT (usado con SEPARATOR) crea un separador que parece sobresalir * de la ventana. * SHADOW_NONE (usado con SEPARATOR) crea un separador sin sombra. * SEPARATOR y VERTICAL generan una línea vertical. * SEPARATOR y HORIZONTAL generan una línea horizontal. * * * La clase Text admite los siguientes estilos: BORDER, SINGLE, * READ_ONLY, LEFT, CENTER, RIGHT, WRAP, PASSWORD y MULTI * (con H_SCROLL, V_SCROLL) * * BORDER crea un cuadro de texto con borde. * SINGLE crea un cuadro de texto que sólo permite una línea. * MULTI crea un cuadro de texto que admite varias líneas. * READ_ONLY crea un cuadro de texto cuyo contenido no se puede editar. * CENTER, LEFT y RIGHT alinean el texto del cuadro de texto con respecto a él. * WRAP hace que el texto dentro del cuadro de texto se pueda dividir en varias líneas, si * resulta necesario. * PASSWORD crea un cuadro de texto que muestra asteriscos cuando se escribe en él. * H_SCROLL crea una barra de desplazamiento horizontal. * V_SCROLL crea una barra de desplazamiento vertical. */ public class EjemploCuadroTexto1 { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(280, 230); shell.setText("Ejemplo 1 de cuadro de texto");

Ejemplo 6: EjemploCuadroTexto1.java

Page 46: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 46 de 114

// Se crean los componentes gráficos. Label l1 = new Label(shell, SWT.NONE); l1.setText("Nombre del usuario:"); l1.setBounds(90, 10, 100, 25); final Text nombreUsuario = new Text(shell, SWT.BORDER); nombreUsuario.setBounds(90, 35, 100, 25); Label etiqueta2 = new Label(shell, SWT.NULL); etiqueta2.setText("Contraseña:"); etiqueta2.setBounds(90, 70, 100, 25); final Text contrasenya = new Text(shell, SWT.BORDER); contrasenya.setEchoChar('*'); contrasenya.setBounds(90, 95, 100, 25); Button validarUsuario = new Button(shell, SWT.PUSH); validarUsuario.setText("Validar usuario"); validarUsuario.setBounds(100, 150, 85, 28); // Tratamiento de sucesos: muy similar a como se hace en Swing. Listener listener = new Listener() { public void handleEvent(Event suceso) { System.out.println( "El nombre del usuario es: " + nombreUsuario.getText()); System.out.println( "La contraseña es: " + contrasenya.getText()); } }; validarUsuario.addListener(SWT.Selection, listener); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } }

Page 47: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 47 de 114

Figura 32. Resultado de ejecutar la clase EjemploCu adroTexto1 import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.graphics.Image; /** * Esta clase genera un cuadro de texto multilínea. * Se necesita incluir el paquete org.eclips.swt.graphics.Image * para poder trabajar con imágenes en SWT. * */ public class EjemploCuadroTexto2 { public static void main(String args []) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 300); shell.setImage(new Image(display, "c:\\Eclipse.jpg")); shell.setText("Ejemplo 2 de cuadro de texto"); // Se crea el cuadro de texto multílinea. Text texto = new Text(shell, SWT.MULTI); // El primer argumento indica la coordenada x del extremo inferior izquierdo del cuadro de // texto; el segundo, la coordenada y del extremo superior izquierdo; los otros dos indican la // anchura y la altura del cuadro de texto, respectivamente.

Ejemplo 7: EjemploCuadroTexto2.java

Page 48: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 48 de 114

texto.setBounds(10, 10, 200, 28); texto.setText( "Línea 1" + System.getProperty("line.separator") + "Línea 2"); shell.open(); while (!shell.isDisposed()){ if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }

Figura 33. Resultado de ejecutar la clase EjemploCu adroTexto2

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.events.*; /** * Esta clase genera tres cuadros de texto y muestra por consola el texto seleccionado * cuando se pasa de uno a otro. * */

Ejemplo 8: EjemploCuadroTexto3.java

Page 49: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 49 de 114

public class EjemploCuadroTexto3 { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(200, 200); shell.setText("Ejemplo 3 de cuadro de texto"); // primer cuadro de texto Text texto1 = new Text(shell, SWT.SINGLE | SWT.BORDER); texto1.setBounds(30, 10, 100, 20); texto1.setTextLimit(11); texto1.setText("javaHispano"); // segundo cuadro de texto Text texto2 = new Text(shell, SWT.SINGLE | SWT.BORDER); texto2.setBounds(30, 40, 100, 20); texto2.setTextLimit(11); // tercer cuadro de texto Text texto3 = new Text(shell, SWT.SINGLE | SWT.BORDER); texto3.setBounds(30, 70, 100, 20); texto3.setTextLimit(11); // gestión de eventos FocusListener focusListener = new FocusListener() { public void focusGained(FocusEvent e) { // Si obtiene el foco se selecciona todo lo que hay en el cuadro de texto. Text texto = (Text) e.widget; texto.selectAll(); } public void focusLost(FocusEvent e) { // Si pierde el foco, muestra el texto seleccionado o un mensaje que // indica que el cuadro de texto estaba vacío. Text texto = (Text) e.widget; if ( texto.getSelectionCount() > 0 ) { if ( texto.getLocation().y == 10 ) { System.out.println("Ha seleccionado en el cuadro de texto 1: " + texto.getText()); } if ( texto.getLocation().y == 40 ) { System.out.println("Ha seleccionado en el cuadro de texto 2: " + texto.getText()); } if ( texto.getLocation().y == 70 ) { System.out.println("Ha seleccionado en el cuadro de texto 3: " + texto.getText()); } } else { System.out.println("No ha seleccionado nada: el cuadro de texto estaba vacío."); } } }; // fin focusListener texto1.addFocusListener(focusListener); texto2.addFocusListener(focusListener); texto3.addFocusListener(focusListener);

Page 50: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 50 de 114

shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }

Figura 34. Resultado de ejecutar la clase EjemploCu adroTexto3

import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.*; /** * Esta clase muestra cómo se usan las etiquetas con SWT. * * La clase Label admite los siguientes estilos: BORDER, CENTER, * LEFT, RIGHT, WRAP y SEPARATOR (con HORIZONTAL, SHADOW_IN, * SHADOW_OUT, SHADOW_NONE y VERTICAL). * * BORDER crea una etiqueta con borde. * CENTER, LEFT y RIGHT alinean el texto de la etiqueta con respecto a la etiqueta. * WRAP hace que el texto dentro de la etiqueta se pueda dividir en varias líneas, si * resulta necesario. * SHADOW_IN (usado con SEPARATOR) crea un separador que parece empotrado * en la ventana.

Ejemplo 9: EjemploEtiqueta.java

Page 51: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 51 de 114

* SHADOW_OUT (usado con SEPARATOR) crea un separador que parece sobresalir * de la ventana. * SHADOW_NONE (usado con SEPARATOR) crea un separador sin sombra. * SEPARATOR y VERTICAL generan una línea vertical. * SEPARATOR y HORIZONTAL generan una línea horizontal. * */ public class EjemploEtiqueta { public static void main(String[] args) { Display display = new Display(); Shell shell = new Shell(); shell.setLayout(new GridLayout(1, false )); shell.setText("Ejemplo de etiquetas"); // Se crea una etiqueta. Label etiqueta1 = new Label(shell, SWT.NONE); etiqueta1.setText("Etiqueta plana"); // Se crea una etiqueta con borde Label etiqueta2 = new Label(shell, SWT.BORDER); etiqueta2.setText("Etiqueta con borde"); // Se crea un separador. Label etiqueta3 = new Label(shell, SWT.SEPARATOR); // Se crea un separador horizontal con sombra. Label etiqueta4= new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.SHADOW_IN); etiqueta4.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); // Se crea una etiqueta con el logotipo de Eclipse. Image imagen = new Image(display, "c:\\Eclipse.jpg"); Label etiqueta5 = new Label(shell, SWT.NONE); etiqueta5.setImage(imagen); shell.open(); shell.pack(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }

Page 52: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 52 de 114

Figura 35. Resultado de ejecutar la clase EjemploEt iqueta

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; /** * Esta clase genera una lista con tres elementos. * * La clase List admite los siguientes estilos: BORDER, H_SCROLL, * V_SCROLL, SINGLE y MULTI. * * BORDER crea un borde alrededor de la lista.

Ejemplo 10: EjemploLista1.java

Page 53: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 53 de 114

* H_SCROLL crea una barra de desplazamiento horizontal para la lista. * V_SCROLL crea una barra de desplazamiento vertical para la lista. * MULTI permite seleccionar a la vez varios elementos. */ public class EjemploLista1 { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 300); shell.setText("Ejemplo 1 de lista"); List lista = new List(shell, SWT.SINGLE | SWT.BORDER); lista.setBounds(40, 40, 80, 60); lista.add("Bolígrafo"); lista.add("Lápiz"); lista.add("Calculadora"); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } }

Figura 36. Resultado de ejecutar la clase EjemploLi sta1

Page 54: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 54 de 114

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.events.*; /** * Esta clase genera una lista con tres elementos que admite selecciones * múltiples. */ public class EjemploLista2 { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 250); shell.setText("Ejemplo 2 de lista"); // El objeto Lista debe definirse como final si se quiere acceder a él desde // el método addSelectionListener(). El argumento SWT.MULTI hace que // se puedan seleccionar varios elementos a la par. final List lista = new List(shell, SWT.MULTI | SWT.BORDER); lista.setBounds(40, 40, 80, 60); lista.add("Bolígrafo"); lista.add("Lápiz"); lista.add("Calculadora"); Button boton = new Button(shell, SWT.PUSH | SWT.BORDER); boton.setBounds(50, 150, 180, 25); boton.setText("Seleccione un elemento de la lista"); // Gestión de sucesos: si se presiona el botón se muestran los // elementos seleccionados. El método getSelection() devuelve // un vector de Strings. boton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { String elementosSeleccionados[] = lista.getSelection(); for (int i = 0; i< elementosSeleccionados.length; i++) { System.out.println(elementosSeleccionados[i]); } } }); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } }

Ejemplo 11: EjemploLista2.java

Page 55: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 55 de 114

Figura 37. Resultado de ejecutar la clase EjemploLi sta2

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.events.*; /** * Esta clase genera una lista con un menú contextual (pop-up) que almacena dos * menús, uno de ellos con dos submenús. * */ public class EjemploLista3 { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 250); shell.setText("Ejemplo 3 de lista"); List lista = new List(shell, SWT.SINGLE | SWT.BORDER); lista.setBounds(80, 40, 100, 60); lista.add("Elemento 1"); lista.add("Elemento 2"); lista.add("Elemento 3"); // Se crea el menú y se añade a la lista. Menu menu = new Menu(shell, SWT.POP_UP); lista.setMenu(menu);

Ejemplo 12: EjemploLista3.java

Page 56: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 56 de 114

// Se crea el menú Archivo. MenuItem archivo = new MenuItem(menu, SWT.CASCADE); archivo.setText("Archivo"); Menu menuArchivo = new Menu(menu); archivo.setMenu(menuArchivo); // Se añaden al menú Archivo los submenús Nuevo y Cerrar MenuItem nuevo = new MenuItem(menuArchivo, SWT.CHECK); nuevo.setText("Nuevo"); MenuItem cerrar = new MenuItem(menuArchivo, SWT.CHECK); cerrar.setText("Cerrar"); // Se crea el menú Salir MenuItem salir = new MenuItem(menu, SWT.PUSH); salir.setText("Salir"); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } }

Figura 38. Resultado de ejecutar la clase EjemploLi sta3

Page 57: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 57 de 114

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.events.*; /** * Esta clase muestra un cuadro combinado en que el usuario puede introducir * elementos hasta alcanzar el valor límite LIMITE. Una vez alcanzado el límite, * por cada elemento que se añada se borrará uno de los que ya había. * * La clase Combo admite los siguientes estilos: BORDER, DROP_DOWN, * READ_ONLY y SIMPLE. * * BORDER crea un borde alrededor del cuadro combinado. * DROP_DOWN crea un cuadro combinado desplegable. * READ_ONLY crea un cuadro combinado que no permite que el usuario introduzca nuevos * elementos o modifique los ya existentes. * SIMPLE crea un cuadro de texto en el que los elementos del cuadro siempre se muestran * como una lista. * */ public class EjemploCuadroCombinado { // Número máximo de elementos que admite el cuadro combinado. final static int LIMITE = 5; public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(210, 100); shell.setText("Ejemplo de cuadro combinado"); final Combo cuadroComb = new Combo(shell, SWT.BORDER | SWT.DROP_DOWN); cuadroComb.setSize( 200, 50); // Tratamiento de sucesos: mientras no se alcance LIMITE, el texto que // introduce el usuario se van añadiendo a la lista de elementos // susceptibles de ser seleccionados. cuadroComb.addListener(SWT.DefaultSelection,new Listener() { public void handleEvent(Event event) { String texto = cuadroComb.getText(); if ( (cuadroComb.indexOf(texto) == -1) && (cuadroComb.getItemCount() >= LIMITE) ) { cuadroComb.remove(0); } cuadroComb.add(texto); } }); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep();

Ejemplo 13: EjemploCuadroCombinado.java

Page 58: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 58 de 114

} } } }

Figura 39. Resultado de ejecutar la clase EjemploCu adroCombinado

import org.eclipse.swt.SWT; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; /** * Esta clase muestra una tabla con cuatro ciudades europeas y su distancia a Madrid. * * La clase Table admite los siguientes estilos: BORDER, H_SCROLL, V_SCROLL, SINGLE, * MULTI, CHECK, FULL_SELECTION y HIDE_SELECTION. * * BORDER crea una tabla con borde. * H_SCROLL crea una tabla con una barra de desplazamiento horizontal. * V_SCROLL crea una tabla con una barra de desplazamiento vertical. * SINGLE crea una tabla que no permite seleccionar a la vez más de una celda. * MULTI crea una tabla que permite la selección de varias celdas a la vez. * CHECK crea una tabla con cuadros de verificación. * FULL_SELECTION crea una tabla en la que, al seleccionar una celda, se selecciona * toda la fila. * HIDE_SELECTION crea una tabla que esconde las celdas seleccionadas cuando la * la tabla pierde el foco. * * La clase TableColum representa una columna de una tabla y admite tres estilos: LEFT, * RIGHT y CENTER, que alinean la columna a la izquierda, a la derecha o al centro. * * La clase TableItem representa una fila de una tabla y no admite ningún estilo. */ public class EjemploTabla1 { public static void main(String args[]) {

Ejemplo 14: EjemploTabla1.java

Page 59: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 59 de 114

Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 250); shell.setText("Ejemplo 1 de tabla"); // Una objeto Table es un widget compuesto. Por ello, conviene usar // algún tipo de esquema (layout). En este caso se usará // el esquema de tipo FillLayout, que distribuye // equitativamente entre los componentes el espacio disponible. shell.setLayout(new FillLayout()); // Se crea la tabla, que permite la selección múltiple de filas. Table tabla = new Table(shell, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION); tabla.setHeaderVisible(true ); tabla.setLinesVisible(true ); // Se crean las columnas. TableColumn columna1 = new TableColumn(tabla, SWT.CENTER); TableColumn columna2 = new TableColumn(tabla, SWT.CENTER); // Se establece el ancho y el nombre de cada columna. columna1.setText("Ciudad"); columna1.setWidth(90); columna2.setText("Distancia"); columna2.setWidth(90); // Se crean y se rellenan las filas. TableItem fila1 = new TableItem(tabla, SWT.NONE); String tmp1[] = {"París", "1100 km"}; fila1.setText(tmp1); TableItem fila2 = new TableItem(tabla, SWT.NONE); String tmp2[] = {"Luxemburgo", "1600 km"}; fila2.setText(tmp2); TableItem fila3 = new TableItem(tabla, SWT.NONE); String tmp3[] = {"Berlín","1800 km"}; fila3.setText(tmp3); // Otra manera de rellenar las filas. TableItem fila4 = new TableItem(tabla, SWT.NONE); fila4.setText(0, "Atenas"); fila4.setText(1, "3500 km"); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } }

Page 60: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 60 de 114

Figura 40. Resultado de ejecutar la clase EjemploTa bla1

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; /** * Esta clase muestra por consola el contenido de todas las celdas de la fila seleccionada por * el usuario. * */ public class EjemploTabla2 { public static void main (String [] args) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 300); shell.setText("Ejemplo 2 de tabla"); // Tabla que admite la selección simultánea de varios elementos. final Table tabla = new Table (shell, SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION); tabla.setLinesVisible (true ); tabla.setHeaderVisible (true ); // Se da nombre a las columnas. for (int i = 1; i < 3; i++) {

Ejemplo 15: EjemploTabla2.java

Page 61: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 61 de 114

TableColumn columna = new TableColumn (tabla, SWT.NULL); columna.setText ("Columna " + i); } // Se rellena la tabla. for (int i = 1; i < 11; i++) { TableItem celda = new TableItem (tabla, SWT.NONE); celda.setText (0, "celda (" + i + " ,1)"); celda.setText (1, "celda (" + i + " ,2)"); } // Se vuelve a calcular el ancho preferido de cada columna. for (int i = 0; i < 2; i++) { tabla.getColumn (i).pack(); } tabla.setSize (800, 800); // Gestión de sucesos: al seleccionar una celda se muestra por consola su texto. tabla.addListener (SWT.Selection, new Listener () { public void handleEvent (Event suceso) { String celda = null ; TableItem celdas[] = tabla.getSelection(); if ( (celdas != null ) && (celdas.length >= 1) ) { System.out.println("Se han seleccionado las celdas: "); System.out.println (celdas[0].getText(0)); System.out.println (celdas[0].getText(1)); } } }); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }

Page 62: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 62 de 114

Figura 41. Resultado de ejecutar la clase EjemploTa bla2

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; /** * Esta clase muestra un panel de lengüetas (TabFolder) con tres lengüetas. Una contiene * un cuadro desplegable (Combo); otra, una etiqueta (Label), y la otra un cuadro de texto (Text). */ public class EjemploTabFolder { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 300); shell.setText("Ejemplo de panel de lengüetas (TabFolder)"); shell.setLayout(new FillLayout()); // Se crea el panel de lengüetas TabFolder panelLengueta = new TabFolder(shell, SWT.NONE);

Ejemplo 16: EjemploTabFolder.java

Page 63: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 63 de 114

// Se crea una lengüeta y se llena con un cuadro desplegable. TabItem lengueta1 = new TabItem(panelLengueta, SWT.NONE); lengueta1.setText("Lengüeta 1"); Combo desplegable = new Combo(panelLengueta, SWT.BORDER); desplegable.add("Soy un cuadro desplegable"); lengueta1.setControl(desplegable); // Se crea una lengüeta y se llena con una etiqueta. TabItem lengueta2 = new TabItem(panelLengueta, SWT.NONE); lengueta2.setText("Lengüeta 2"); Label etiqueta = new Label(panelLengueta, SWT.BORDER); etiqueta.setText("Soy una etiqueta"); lengueta2.setControl(etiqueta); // Se crea una lengüeta y se llena con un cuadro de texto. TabItem lengueta3 = new TabItem(panelLengueta, SWT.NONE); lengueta3.setText("Lengüeta 3"); Text cuadroTexto = new Text(panelLengueta, SWT.NONE); cuadroTexto.setText("Soy un cuadro de texto"); lengueta3.setControl(cuadroTexto); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } }

Figura 42. Resultado de ejecutar la clase EjemploTa bFolder

Page 64: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 64 de 114

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; /** * Esta clase genera un árbol del que cuelgan varios nodos. * * La clase Tree actúa como un contenedor de objetos TreeItem. * La clase Tree admite los siguientes estilos: BORDER, * H_SCROLL, V_SCROLL, SINGLE, MULTI y CHECK. * * BORDER crea un árbol con borde. * H_SCROLL y V_SCROLL crean un árbol con una barra de desplazamiento horizontal o * vertical, respectivamente * SINGLE crea un árbol que sólo permite seleccionar un nodo o elemento a la vez. * MULTI crea un árbol que permite que se seleccionen a la vez varios nodos o elementos. * CHECK crea un árbol con cuadros de verificación. * * Los métodos más usados de Tree son: * 1) getSelection() devuelve un vector con los TreeItems que están seleccionados. * 2) getSelectionCount() devuelve el número de elementos seleccionados. * 3) removeAll() borra todos los elementos del árbol. * 4) selectAll() selecciona todos los elementos del árbol. * 5) deselectAll() quita la selección de todos los elementos seleccionados del árbol. * 6) setSelection(TreeItem[]) Seleccionan los elementos establecidos en el vector pasado como * argumento. * * Los métodos más usados de TreeItem son: * 1) getChecked() devuelve true si el elemento está marcado, y false en caso contrario. * 2) getExpanded () devuelve true si el elemento está expandido, y false en caso contrario. * 3) setChecked (boolean) establece si el elemento está marcado o no. * 4) setExpanded(boolean) establece si el elemento está expandido o no. * 5) setImage(Image) establece una imagen para el elemento. Si el argumento es null, no se * mostrará ninguna imagen. * 4) setText(String) establece el texto del elemento. */ public class EjemploArbol { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 300); shell.setText("Ejemplo de árbol"); shell.setLayout(new FillLayout()); // Se crea el árbol. Tree arbol = new Tree(shell, SWT.BORDER); // Se crea el nodo 1 y sus subnodos. TreeItem nodo1 = new TreeItem(arbol, SWT.NONE);

Ejemplo 17: EjemploArbol.java

Page 65: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 65 de 114

nodo1.setText("Nodo 1"); TreeItem nodo11 = new TreeItem(nodo1, SWT.NONE); nodo11.setText("Nodo 1.1"); TreeItem nodo111 = new TreeItem(nodo11, SWT.NONE); nodo111.setText("Nodo 1.1.1"); // Se crea el nodo 2 y sus subnodos. TreeItem nodo2 = new TreeItem(arbol, SWT.NONE); nodo2.setText("Nodo 2"); TreeItem nodo21 = new TreeItem(arbol, SWT.NONE); nodo21.setText("Nodo 2.1"); TreeItem nodo22 = new TreeItem(arbol, SWT.NONE); nodo22.setText("Nodo 2.2"); // Se expande el nodo 1 y su subnodo. nodo1.setExpanded( true ); nodo11.setExpanded(true ); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }

Figura 43. Resultado de ejecutar la clase EjemploAr bol

Page 66: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 66 de 114

import org.eclipse.swt.SWT; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; /** * Esta clase muestra botones, de distintos tipos, organizados según el layout * RowLayout, que permite organizar los controles una fila o una columna, sin forzar a que tengan * el mismo tamaño (si no caben en una sola fila o columna, se muestran en varias). * * Por ahora, SWT admite seis layouts: FillLayout, StackLayout, GridLayout, FormLayout, * RowLayout y CustomLayout. */ public class EjemploRowLayout { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(250, 250); shell.setText("Ejemplo de RowLayout"); // columnas horizontales shell.setLayout(new RowLayout(SWT.HORIZONTAL)); for (int i = 0; i < 9; i++) { Button boton = new Button(shell, SWT.ARROW); boton.setText("Botón no. " + i); } for (int i = 0; i < 9; i++) { Button boton = new Button(shell, SWT.PUSH); boton.setText("Botón no. " + i); } for (int i = 0; i < 9; i++) { Button boton = new Button(shell, SWT.RADIO); boton.setText("Botón no. " + i); } shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } }

Ejemplo 18: EjemploRowLayout.java

Page 67: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 67 de 114

Figura 44. Resultado de ejecutar la clase EjemploRo wLayout

import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; /** * Esta clase genera 25 etiquetas organizadas según el layout GridLayout, que * permite crear múltiples filas y columnas, es decir, una red de controles. * * Por ahora, SWT admite seis layouts: FillLayout, StackLayout, GridLayout, FormLayout, * RowLayout y CustomLayout. */ public class EjemploGridLayout { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(400, 300);

// El primer argumento indica es el número de columnas. // El segundo argumento (booleano) indica si se desea tomar el espacio mínimo // para columna (false) o no (true). shell.setLayout(new GridLayout(4, false )); for (int i = 0; i < 25; i++) { Label etiqueta = new Label(shell, SWT.BORDER | SWT.CENTER); etiqueta.setText("Etiqueta no. " + i);

Ejemplo 19: EjemploGridLayout.java

Page 68: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 68 de 114

} shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } }

Figura 45. Resultado de ejecutar la clase EjemploGr idLayout

import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.graphics.*; // incluye la clase Color /** * Esta clase genera una ventana con una etiqueta, un botón y un área de texto, organizados * mediante el layout FormLayout. Como una imagen vale más que mil palabras, la * mejor explicación para lo que hace esta clase está en la figura 46. * * La clase FormLayout utiliza la clase FormData para colocar los controles donde correspon- * da, con el tamaño adecuado. FormData permite especificar la anchura y la longitud de * un control dentro de un FormLayout. * A su vez, la clase FormData usa la clase FormAttachment para especificar los bordes * de un control en el layout. Estos bordes se pueden dar como posiciones absolutas en píxeles * (poco recomendable) o como porcentajes (en tanto por ciento) del ancho o del alto del * compuesto en que se haya el control. * Mirando la figura 46, se puede deducir la correspondencia entre el código y la interfaz. */ public class EjemploFormLayout { public static void main(String args[]) {

Ejemplo 20: EjemploFormLayout.java

Page 69: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 69 de 114

Display display = new Display(); Shell shell = new Shell(display); shell.setSize(400, 400); shell.setText("Ejemplo 1 de FormLayout"); FormLayout layout= new FormLayout(); shell.setLayout (layout); Label etiqueta1 = new Label (shell, SWT.CENTER | SWT.BORDER); etiqueta1.setText("Etiqueta 1"); etiqueta1.setBackground(new Color(null , 191, 191, 255)); Label etiqueta2= new Label(shell, SWT.CENTER | SWT.BORDER); etiqueta2.setText("Etiqueta 2"); etiqueta2.setBackground(new Color(null , 255, 255, 179)); Label etiqueta3= new Label(shell, SWT.CENTER | SWT.BORDER); etiqueta3.setText("Etiqueta 3"); etiqueta3.setBackground(new Color(null , 255, 202, 149)); FormData data1 = new FormData(); data1.left = new FormAttachment(0, 20); data1.right = new FormAttachment(25, 0); etiqueta1.setLayoutData(data1); // El control a la izquierda de etiqueta2 es etiqueta1. FormData data2 = new FormData(); data2.left = new FormAttachment(etiqueta1, 15); data2.right= new FormAttachment(90, -15); etiqueta2.setLayoutData(data2); // El control encima de etiqueta3 es etiqueta1. FormData data3 = new FormData(); data3.left = new FormAttachment(25, 15); data3.right = new FormAttachment(100, -15); data3.top = new FormAttachment(etiqueta2, 18); data3.bottom = new FormAttachment(100, -21); etiqueta3.setLayoutData(data3); shell.pack(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } }

Page 70: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 70 de 114

Figura 46. Resultado de ejecutar la clase EjemploFo rmLayout (1: etiqueta1; 2: etiqueta2; 3: etiqueta3)

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; /** * Esta clase genera un diálogo de directorios y muestra por la consola el directorio * seleccionado. * * La clase DirectoryDialog admite los siguientes estilos: * 1) OPEN permite que el usuario escoja un directorio. * 2) MULTI permite que el usuario escoja varios directorios a la vez. * * Los métodos más usados de DirectoryDialog son: * 1) open() abre el cuadro de diálogo y devuelve el nombre del directorio seleccionado. * Si no se ha seleccionado ninguno, devuelve null. * 2) setFilterPath() permite especificar una cierta cadena de caracteres para la búsqueda * de directorios * 4) setMessage() permite colocar un mensaje sobre el cuadro de diálogo. */

Ejemplo 21: EjemploDialogoDirectorios.java

Margen izquierdo (1): 20

Margen izquierdo (2 y 3): 15

25%

Margen derecho (2 y

3): -15

90%

100%

100%

18

21

Miguel Ángel Abián, marzo de 2005

Page 71: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 71 de 114

public class EjemploDialogoDirectorios { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 400); shell.setText("Ejemplo diálogo de directorios"); DirectoryDialog dialogo = new DirectoryDialog(shell); dialogo.setMessage("Elija un directorio"); String directorio = dialogo.open(); if (directorio != null ) { System.out.println("Directorio seleccionado:" + directorio); } shell.open(); display.dispose(); } }

Figura 47. Resultado de ejecutar la clase EjemploDi alogoDirectorios

Page 72: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 72 de 114

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; /** * Esta clase genera un diálogo de archivos y muestra por consola el archivo elegido. * * La clase DialogFile admite los siguientes estilos: * 1) SAVE permite hacer diálogos para guardar archivos. * 2) OPEN permite que el usuario escoja un único archivo. * 3) MULTI permite que el usuario escoja varios archivos a la vez. * * Los métodos más usados de DialogFile: * 1) open() abre el cuadro de diálogo y devuelve el nombre del archivo seleccionado. * Si no se ha seleccionado ninguno, devuelve null. Si se trabaja con el estilo MULTI, * este método devolverá el nombre de un solo archivo. Si se quiere saber todos los * que han sido seleccionados, debe usarse getFileNames(). * 2) setFilterExtensions() permite especificar una cierta extensión para los archivos que * se buscan. */ public class EjemploDialogoArchivos { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 400); shell.setText("Ejemplo de diálogo de directorios"); FileDialog dialogo = new FileDialog(shell, SWT.SINGLE); dialogo.setFilterExtensions(new String[] {"*.java"}); String archivo = dialogo.open(); if (archivo != null ) { System.out.println("Ha seleccionado el archivo " + archivo); } shell.open(); display.dispose(); } }

Ejemplo 22: EjemploDialogoArchivos.java

Page 73: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 73 de 114

Figura 48. Resultado de ejecutar la clase EjemploDi alogoArchivos

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; /** * Esta clase genera un diálogo de mensaje con tres botones y muestra por consola la opción * elegida. * * Los estilos que admite la clase MessageBox son: * 1) ICON_ERROR, ICON_INFORMATION, ICON_QUESTION, ICON_WARNING e * ICON_WORKING permiten elegir el icono del diálogo. * 2) OK o OK | CANCEL para elegir botones del tipo OK o OK/CANCELAR. * 3) YES | NO, YES | NO | CANCEL para elegir botones del tipo SI, NO, CANCELAR. * 4) RETRY | CANCEL para elegir botones del tipo REINTENTAR/CANCELAR. * 5) ABORT | RETRY | IGNORE para elegir botones del tipo ANULAR/REINTENTAR/OMITIR. * * Los iconos indican lo siguiente: * ERROR_ICON: error. * ICON_INFORMATION: se muestra un mensaje al usuario * ICON_QUESTION: se necesita que el usuario dé una respuesta (SI, NO, CANCELAR...) * ICON_WARNING: se avisa al usuario de que la pregunta puede tener consecuencias no deseadas. * ICON_WORKING: la aplicación que se ejecuta está realizando alguna tarea.

Ejemplo 23: EjemploDialogoMensaje1.java

Page 74: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 74 de 114

*/ public class EjemploDialogoMensaje1 { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(0, 0); shell.setText("Ejemplo 1 de diálogo de mensaje"); MessageBox dialogo = new MessageBox(shell, SWT.YES | SWT.NO | SWT.CANCEL | SWT.ICON_QUESTION); dialogo.setMessage("Qué extraño. Problemas. ¿Desea continuar?"); int respuesta = dialogo.open(); if (respuesta == SWT.YES) { System.out.println("Ha elegido continuar"); } else if (respuesta == SWT.NO) { System.out.println("Ha elegido no continuar"); } else if (respuesta == SWT.CANCEL) { System.out.println("Ha elegido cancelar"); } shell.open(); display.dispose(); } }

Figura 49. Resultado de ejecutar la clase EjemploDi alogoMensaje1

Page 75: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 75 de 114

import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; /** * Esta clase genera una ventana con un botón de tipo PUSH. Al pulsarlo, aparece un * mensaje de diálogo con botones ANULAR/REINTENTAR/OMITIR. Al elegir una opción, * se muestra por consola la elegida. * */ public class EjemploDialogoMensaje2 { public static void main(String args[]) { Display display = new Display(); final Shell shell = new Shell(display); shell.setLayout(new RowLayout()); shell.setSize(300, 300); shell.setText("Ejemplo 2 de mensaje de diálogo"); Button pulsar = new Button(shell, SWT.PUSH); pulsar.setText("Pulse aquí"); pulsar.addListener(SWT.Selection, new Listener() { public void handleEvent(Event e) { int respuesta = 0; MessageBox dialogo = new MessageBox(shell, SWT.ICON_WARNING | SWT.ABORT | SWT.RETRY | SWT.IGNORE); dialogo.setMessage("Mensaje para el usuario"); respuesta = dialogo.open(); if (respuesta == SWT.ABORT) { System.out.println("Se ha seleccionado el botón ANULAR"); } if (respuesta == SWT.RETRY) { System.out.println("Se ha seleccionado el botón REINTENTAR"); } if (respuesta == SWT.IGNORE) { System.out.println("Se ha seleccionado el botón OMITIR"); } } }); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } }

Ejemplo 24: EjemploDialogoMensaje2.java

Page 76: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 76 de 114

}

}

Figura 50. Resultado de ejecutar la clase EjemploDi alogoMensaje2

Page 77: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 77 de 114

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.graphics.*; // incluye la clase Color /** * Esta clase genera un diálogo de color y muestra por consola las componentes * cromáticas RGB del color elegido. Si no se elige ningún color, la aplicación * termina. * * La clase ColorDialog permite seleccionar un color de una paleta de colores. Su * método open() abre el cuadro de diálogo y devuelve el color seleccionado en * forma de un objeto de tipo RGB. Si no se selecciona ningún color, open() devuelve * null. */ public class EjemploDialogoColor { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 400); Color color = null ; ColorDialog dialogo = new ColorDialog(shell); if (color !=null ) { dialogo.setRGB(color.getRGB()); } else { dialogo.setRGB(null ); } while (true ) { if (dialogo.open() != null ) { // Se había elegido un color antes. if (color != null ) { // Es crucial la limpieza del objeto color por parte del programador. // En SWT, el recolector de basura no funciona: los objetos deben // liberarse usando su método dispose(). color.dispose(); } color = new Color(display, dialogo.getRGB()); System.out.println("Rojo: " + color.getRed()); System.out.println("Azul: " + color.getBlue()); System.out.println("Verde: " + color.getGreen()); } // No se ha elegido un color. else { System.exit(0); }

Ejemplo 25: EjemploDialogoColor.java

Page 78: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 78 de 114

} } }

Figura 51. Resultado de ejecutar la clase EjemploDi alogoColor. (Reconozco que queda mucho más vistoso en un Macintosh, pero n o tengo ninguno a mano.)

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.layout.*; /** * Esta clase muestra un cuadro de diálogo desde donde se puede seleccionar un * tipo de letra (nombre, tamaño, negrita/cursiva/...) y crea una etiqueta con la * leyenda "Colabore con javaHispano" con el tipo de letra elegido. * * La clase FontDialog permite al usuario seleccionar un tipo de letra de las disponibles * en el sistema. Como algunos tipos de letras son específicos de la plataforma en la que * se trabaja, SWT trabaja con la clase FontData como intermediaria. * El método open() de la clase FontDialog devuelve un objeto FontData que representa * al color seleccionado (si no se selecciona nada, open() devuelve null). * FontData admite argumentos como los de la siguiente línea * FontData defaultFont = new FontData("Courier", 14, SWT.BOLD); */

Ejemplo 26: EjemploDialogoTipoLetra.java

Page 79: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 79 de 114

public class EjemploDialogoTipoLetra { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(300, 100); shell.setText("Ejemplo de diálogo para elegir tipo de letra"); shell.setLayout(new FillLayout(SWT.CENTER)); FontDialog fd = new FontDialog(shell); FontData fontData = fd.open(); if (fontData != null ) { Font f = new Font(display, fontData); Label etiqueta = new Label(shell, SWT.BORDER | SWT.CENTER); etiqueta.setText("Colabore con javaHispano"); etiqueta.setFont(f); // En SWT, el recolector de basura no funciona: los objetos deben // liberarse usando su método dispose(). f.dispose(); } // Si no se ha elegido nada, se sale de la aplicación. else { display.dispose(); System.exit(0); } shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }

Page 80: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 80 de 114

Figura 52. Resultado de ejecutar la clase EjemploDi alogoTipoLetra. Haga caso al mensaje, por favor

Page 81: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 81 de 114

import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; /** * Esta clase llama a la clase EjemploGrupo para mostrar un grupo * de controles. */ public class PrincipalGrupo { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setSize(200, 200); shell.setText("Ejemplo de grupo"); EjemploGrupo ejGrupo = new EjemploGrupo(shell); ejGrupo.setLayout(new FillLayout(SWT.CENTER)); ejGrupo.pack(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } }

import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.layout.*; /** * Esta clase representa a un grupo con varios controles. * * La clase Group admite los estilos SHADOW_ETCHED_IN, * SHADOW_ETCHED_OUT, SHADOW_IN, SHADOW_OUT y SHADOW_NONE y * NO_RADIO_GROUP * Todos, excepto el último, no tienen efecto en Windows (en Motif sí, por ejemplo). * * La clase Composite admite los estilos BORDER (borde), * H_SCROLL (barra de deslizamiento horizontal) y * V_SCROLL (barra de deslizamiento vertical).

Ejemplo 27a: PrincipalGrupo.java

Ejemplo 27b: EjemploGrupo.java

Page 82: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 82 de 114

*/ public class EjemploGrupo extends Composite { public EjemploGrupo(Composite comp) { super (comp, SWT.V_SCROLL | SWT.H_SCROLL); Group grupo = new Group(this , SWT.SHADOW_NONE); grupo.setText("Grupo de controles"); grupo.setLayout(new RowLayout(SWT.VERTICAL)); Button boton1 = new Button (grupo, SWT.PUSH | SWT.CENTER); boton1.setText("Botón normal"); Button boton2 = new Button(grupo, SWT.RADIO | SWT.CENTER); boton2.setText("Botón redondo"); Label etiqueta = new Label(grupo, SWT.BORDER | SWT.CENTER); etiqueta.setText("Etiqueta"); Text areaTexto = new Text(grupo, SWT.BORDER | SWT.CENTER | SWT.MULTI | SWT.V_SCROLL); areaTexto.setText("Área de texto multilínea"); } }

Figura 53. Resultado de ejecutar la clase Principal Grupo

Page 83: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 83 de 114

import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.browser.*; /** * Esta clase abre un navegador con el URL http://www.galeria.sonic.pl/DaliGal/Gal12/1935_02.htm. * El navegador que se abra dependerá de la configuración del sistema. * * La clase Browser permite incluir el navegador web del usuario en una aplicación * con SWT y usarlo para ver código HTML sin que se necesite escribir código que * actualice cada cierto tiempo lo que se muestra en el navegador. * * La clase Browser sólo está disponible en Eclipse 3.0 y posteriores (cuando escribo * esto todavía no se encuentre disponible para algunas plataformas). * En las versiones 2.x de Eclipse, en Windows se haría este programa empleando el * paquete org.eclipse.swt.ole.win32.* y la clase SWT OleControlSite. * */ public class EjemploNavegador { public static void main(String args[]) { Display display = new Display(); Shell shell = new Shell(display); shell.setText("Ejemplo de apertura de un navegador desde SWT"); shell.setSize(800, 600); Label etiqueta = new Label(shell, SWT.BORDER | SWT.CENTER); etiqueta.setBounds(190, 0, 400, 25); etiqueta.setText("La URL es http://www.galeria.sonic.pl/DaliGal/Gal12/1935_02.htm"); try { Browser navegador = new Browser(shell, SWT.BORDER); navegador.setUrl("http://www.galeria.sonic.pl/DaliGal/Gal12/1935_02.htm"); navegador.setBounds(1, 1, 799, 599); } // Si no se encuentra ningún navegador, se lanzará una // excepción SWTError. catch (SWTError e) { System.out.println("No se encuentra ningún navegador en su sistema."); e.printStackTrace(); System.exit(-1); } shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } }

Ejemplo 28: EjemploNavegador.java

Page 84: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 84 de 114

display.dispose(); } }

Figura 54. Resultado de ejecutar la clase EjemploNa vegador

Page 85: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 85 de 114

16. JFace Si ha ojeado los ejemplos del apartado anterior, habrá notado que los controles

SWT vienen a ser una versión ampliada y camaleónica de los controles AWT, disponibles desde la primera versión de Java. Así pues, SWT está muchísimo más limitado que Swing, basado en la arquitectura Modelo-Vista-Controlador. Las facilidades que la plataforma Eclipse proporciona para construir interfaces gráficas espectaculares no provienen de SWT, sino de la unión de SWT con JFace. En otras palabras, lo que luce de Eclipse es JFace.

JFace es una biblioteca gráfica construida sobre SWT. JFace usa los componentes

SWT (lo contrario no es cierto) para construir controles más complejos. He aquí algunas de las características más relevantes de JFace (por motivos de espacio, omito cualquier explicación sobre la manera como se implementan):

• Permite separar los componentes de la interfaz gráfica de usuario y las respuestas a sus sucesos. Consideremos, vaya por caso, una interfaz con muchos botones que respondan de la misma manera (lanzando un cuadro de diálogo, cerrando la aplicación...). En SWT habría que escribir el mismo código de tratamiento del suceso para todos los botones (SWT exige que cada suceso sea declarado y procesado individualmente). En cambio, JFace permite que el programador defina una respuesta común en un objeto Action y que la asigne a todos los botones. En general, una respuesta o acción puede ser compartida por todos los componentes o widgets que uno quiera (botones, menús, árboles...). La separación entre componentes y respuestas a sucesos conlleva dos ventajas. Por un lado, evita duplicar código. Por otro, permite que los diseñadores de interfaces gráficas y los programadores trabajen independientemente, sin mezclar el código de unos y otros.

• Proporciona clases de tipo Viewer (visor), que se encargan de tareas comunes como ordenar o actualizar los componentes. Estas clases permiten trabajar con elementos del modelo en lugar de con widgets. Por ejemplo, la clase TreeViewer tiene métodos que permiten trabajar con los objetos del modelo del usuario, en lugar de trabajar con objetos gráficos del tipo TreeItem, más primitivos.

• Define cuadros de diálogo y asistentes (wizards; un asistente es un diálogo especializado que guía al usuario para realizar tareas como instalar un impresora o conectarse a Internet), que responden a muchas necesidades habituales de los programadores (MessageDialog, InputDialog, PreferenceDialog...).

• Permite registrar objetos como Color, Font o Image, de manera que los recursos asociados puedan liberarse cuando ya no se usen aquéllos. En SWT resulta conveniente destruir enseguida los objetos Color, Font e Image que ya no se utilizen, pues no hay un recolector de basura automático que se relama pensando en los recursos huérfanos que va a devorar ni esos objetos se destruyen cuando se elimina el componente donde se usan. Si el programador no libera explícitamente los recursos que no necesita, se perjudica el rendimiento del sistema y se favorece que aparezcan fallos de memoria. Con JFace, en cambio, se pueden usar

Page 86: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 86 de 114

clases como ColorRegistry, FontRegistry o ImageRegistry, que liberan automáticamente todos los recursos asociados a colores, tipos de letra o imágenes cuando se destruye el componente para el cual se crearon.

La estructura típica de una aplicación que usa JFace se muestra en el siguiente

ejemplo:

import org.eclipse.jface.window.*; import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; /** * Esta clase es la versión de HolaMundo con SWT/JFace. */ public class SaludosJFace extends ApplicationWindow { // Constructor. public SaludosJFace() { super (null ); } public static void main(String[] args) { SaludosJFace saludo = new SaludosJFace(); // La ventana aparecerá hasta que el usuario la cierre. saludo.setBlockOnOpen(true ); // Se muestra la ventana del modo dictado por el objeto // Composite devuelto por el método createContents(). saludo.open(); //Una vez cerrada la ventana, se liberan sus recursos. Display.getCurrent().dispose(); } // Asocia un objeto Composite para controlar la interfaz gráfica. protected Control createContents(Composite padre) { Label etiqueta= new Label(padre, SWT.CENTER); etiqueta.setText("Saludos con JFace"); return padre; } }

Ejemplo 29: SaludosJFace.java

Page 87: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 87 de 114

Figura 55. Resultado de ejecutar la clase SaludosJF ace Para que el ejemplo funcione, se precisa añadir los siguientes archivos JAR

mediante la pestaña Libraries en el Java Build Path de Eclipse (véase la figura 56; el ejemplo es para Windows y para la versión 3.0.1 de Eclipse):

• INSTALLDIR\eclipse\plugins\org.eclipse.jface_3.0.1\jface.jar

• INSTALLDIR\eclipse\plugins\org.eclipse.core.runtime_3.1.0\runtime.jar

• INSTALLDIR\eclipse\plugins\org.eclipse.ui.workbench_3.1.0\workbench.jar

• INSTALLDIR\eclipse\plugins\org.eclipse.core.boot.3.0.1\boot.jar

Figura 56. Configuración de Eclipse para trabajar c on JFace

Page 88: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 88 de 114

La clase más importante de JFace es ApplicationWindow. Para el usuario, un objeto

ApplicationWindow es una ventana principal que puede contener controles. Esta clase crea su propio shell y permite personalizarlo de manera más rápida y versátil que con SWT. También separa, por un lado, el aspecto de la interfaz gráfica de usuario y, por otro, su comportamiento.

ApplicationWindow cuenta con métodos como addMenuBar(), addToolBar() y setDefaultImage(), los cuales permiten incluir al instante barras de menús, barras de herramientas e imágenes.

En la jerarquía de clases de JFace, ApplicationWindow desciende directamente de la clase Window (contenida en el paquete org.eclipse.jface.window ). Window es una clase abstracta con unos métodos que sus subclases deben sobreescribir:

• close: Libera los recursos SWT. • configureShell: Establece las propiedades del shell antes de que se abra la

ventana. • createContents: Crea los controles antes de que se abra la ventana. • getInitialSize: Especifica el tamaño inicial para el shell. • getInitialLocation: Especifica la posición inicial del shell. • getShellListener: Recibe los sucesos del shell. • getToolTipText: Añade sugerencias o descripciones emergentes (tooltips). • handleFontChange: Implementa la respuesta a cambios en el tipo de letra. • HandleShellCloseEvent: Especifica el comportamiento del shell cuando se

cierra.

Todas las instancias de las subclases de Window son invisibles hasta que se llama a su método open().

Veamos otros ejemplos de uso del componente JFace:

import org.eclipse.jface.window.*; import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.graphics.*; /* * Esta clase muestra una ventana que muestra un mensaje SWT de SI/NO cuando se intenta * cerrarla. * * El método createContents() se sobreescribe para crear y devolver los controles SWT * que aparecerán en la ventana. * * Al reescribir el método canHandleShellCloseEvent() se establece si la * ventana maneja el suceso de cierre o si no hace nada. * Si no se reescribe, la implementación por defecto devuelve true, lo * cual produce que se llame al método handleShellCloseEvent(). * * El método handleShellCloseEvent() se llama cuando se aprieta el botón de cierre, * el menú de cierre o la tecla ESCAPE. Por omisión, este último método cierra

Ejemplo 30: MensajeJFace.java

Page 89: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 89 de 114

* la ventana mediante close(). Al reescribirlo, se define el comportamiento * de la ventana cuando se intente cerrarla. * * El método getInitialLocations() devuelve la posición inicial para el shell. * * El método getInitialSize() devuelve el tamaño inicial del shell. * * El método getShell() devuelve el shell asociado a la ventana. * */ public class MensajeJFace extends ApplicationWindow { public MensajeJFace() { super (null ); } public static void main(String[] args) { ApplicationWindow ventana = new MensajeJFace(); ventana.setBlockOnOpen(true ); ventana.open(); Display.getCurrent().dispose(); } protected Control createContents(Composite padre) { getShell().setText("Ejemplo de uso de mensajes con JFace"); Composite contenedor = new Composite(padre, SWT.BORDER); return contenedor; } // Comportamiento al intentar cerrar la ventana protected boolean canHandleShellCloseEvent() { boolean bool = false ; MessageBox cuadroMensaje = new MessageBox(getShell(), SWT.YES | SWT.NO | SWT.ICON_QUESTION); cuadroMensaje.setText("Mensaje con JFace"); cuadroMensaje.setMessage("¿Desea cerrar la aplicación?"); int respuesta = cuadroMensaje.open(); if (respuesta == SWT.NO) { return bool; } else { bool = true ; return bool; } } // Tamaño inicial protected Point getInitialSize() { return new Point(400, 300); } // Posición inicial protected Point getInitialLocation() { return new Point(400, 300);

Page 90: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 90 de 114

} }

Figura 57. Resultado de ejecutar la clase MensajeJF ace

import org.eclipse.swt.*; import org.eclipse.swt.events.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; import org.eclipse.jface.dialogs.*; /** * Esta clase muestra un diálogo personalizado con tres botones. Al apretar * uno, se muestra un mensaje informativo donde aparece el botón seleccionado. * Nótese que el diálogo JFace se crea sobre un shell definido mediante SWT, no * mediante JFace. Podría usarse también con una ApplicationWindow. * */

Ejemplo 31: DialogoPersonalizado1.java

Page 91: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 91 de 114

public class DialogoPersonalizado1 { public static void main(String[] args) { Display display = new Display(); final Shell shell = new Shell(display); shell.setText("Ejemplo de diálogo JFace personalizado"); shell.setBounds(100, 100, 200, 100); shell.setLayout(new FillLayout()); final Button boton = new Button(shell, SWT.PUSH); boton.setText("Pulse aquí"); boton.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { String tipo[] = {"Botón 1", "Botón 2", "Botón 3"}; MessageDialog dialogo = new MessageDialog(shell, "Mensaje para el usuario", null , "Mensaje informativo", MessageDialog.INFORMATION, tipo, 2); int botonPulsado = dialogo.open(); String texto ; if (botonPulsado == -1) { texto = "No se ha apretado ningún botón"; } else { botonPulsado++; // El primer botón tiene el índice 0 texto = "Se ha apretado el botón " + botonPulsado; } MessageDialog.openInformation(shell, "Mensaje", texto); } }); shell.pack(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } }

Page 92: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 92 de 114

Figura 58. Resultado de ejecutar la clase DialogoPe rsonalizado1

import org.eclipse.swt.widgets.*; import org.eclipse.jface.dialogs.IDialogConstants; /** * Esta clase muestra un diálogo personalizado con una etiqueta, un cuadro * de texto y dos botones. La implementación del diálogo está en la clase * Dialogo. Al apretar uno de los botones, se muestra un mensaje por consola. * * Nótese que el diálogo JFace se crea sobre un shell definido mediante SWT, no * mediante JFace. Podría usarse también con una ApplicationWindow * */ public class DialogoPersonalizado2 { public static void main(String args[]) {

Ejemplo 32a: DialogoPersonalizado2.java

Page 93: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 93 de 114

Display display = new Display(); Shell shell = new Shell(display); shell.setSize(250, 120); Dialogo dialogo = new Dialogo(shell); dialogo.create(); int respuesta = dialogo.open(); if (respuesta == IDialogConstants.ABORT_ID) { System.out.println("Ha apretado el botón de ANULAR"); } else if (respuesta == IDialogConstants.CLOSE_ID) { System.out.println("Ha apretado el botón de CERRAR"); } else { System.out.println("Ha cancelado el cuadro de diálogo"); } display.dispose(); } }

import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.swt.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; /** * Esta clase contiene la implementación de un diálogo personalizado con una * etiqueta, un cuadro de texto y dos botones. JFace proporciona facilidades * para crear directamente los botones más usuales. * */ public class Dialogo extends Dialog { protected Dialogo(Shell shell) { super(shell); } protected void configureShell(Shell shell) { super.configureShell(shell); } // Se configura la interfaz gráfica del diálogo. protected Control createDialogArea(Composite padre) { Composite composite = (Composite) super.createDialogArea(padre); composite.setLayout(new FillLayout(SWT.VERTICAL)); Label etiqueta = new Label(composite, SWT.CENTER);

Ejemplo 32b: Dialogo.java

Page 94: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 94 de 114

etiqueta.setText("Ejemplo 2 de diálogo personalizado"); Text texto = new Text(composite, SWT.CENTER | SWT.BORDER); texto.setText("Pulse uno de los dos botones"); return composite; } // Se configuran los botones para la barra de botones. protected void createButtonsForButtonBar(Composite padre) { createButton(padre, IDialogConstants.ABORT_ID, IDialogConstants.ABORT_LABEL, true); createButton(padre, IDialogConstants.CLOSE_ID, IDialogConstants.CLOSE_LABEL, false); } // Tratamiento de sucesos. Se devuelve el identificador // del botón apretado. Cuando se llame al método open() de // un objeto Dialogo, se devolverá ese identificador. protected void buttonPressed(int IdBoton) { if (IdBoton== IDialogConstants.ABORT_ID || IdBoton== IDialogConstants.CLOSE_ID) { setReturnCode(IdBoton); close(); } } }

Figura 59. Resultado de ejecutar la clase DialogoPe rsonalizado2

Page 95: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 95 de 114

Para explicitar la separación que permite JFace entre la interfaz gráfica y su comportamiento, incluyo el siguiente ejemplo, que usa una subclase de la clase Action.

import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.jface.action.*; import org.eclipse.jface.dialogs.*; // necesario para el MessageDialog de JFace import org.eclipse.jface.window.*; /* * Esta clase muestra cómo se puede usar un objeto Action para gestionar * los sucesos de varios controles (en este ejemplo, dos menús). Mediante * el objeto Action se consigue responder con un mensaje de información * a sucesos de dos objetos distintos. Se utiliza la clase MessageDialog de JFace. * * Al reescribir el método canHandleShellCloseEvent() se establece si la * ventana maneja el suceso de cierre o si no hace nada. * Si no se reescribe, la implementación por defecto devuelve true, lo * cual produce que se llame al método handleShellCloseEvent(). * * El método handleShellCloseEvent() se llama cuando se aprieta el botón de cierre, * el menú de cierre o la tecla ESCAPE. Por omisión, este último método cierra * la ventana mediante close(). Al reescribirlo, se define el comportamiento * de la ventana cuando se intente cerrarla. * * El método createContents() se sobreescribe para crear y devolver los * controles SWT que aparecerán en la ventana. * * El método createMenuManager se sobreescribe para especificar y devolver * los menús de la ventana. * * El método createToolBarManager se sobreescribe para especificar y devolver * los elementos de la barra de herramientas. * * El método getShell() devuelve el shell asociado a la ventana. * */ public class EjemploAction extends ApplicationWindow { private InformacionAction infoAction; public EjemploAction() { super (null ); infoAction = new InformacionAction(this ); addMenuBar(); addToolBar(SWT.WRAP); } public static void main(String args[]) { EjemploAction ventana = new EjemploAction(); ventana.setBlockOnOpen(true );

Ejemplo 33a: EjemploAction.java

Page 96: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 96 de 114

ventana.open(); Display.getCurrent().dispose(); } protected Control createContents(Composite padre) { Group grupo = new Group(padre, SWT.CENTER); return grupo; } protected MenuManager createMenuManager(){ MenuManager barraMenus = new MenuManager(""); MenuManager menu1 = new MenuManager("Ayuda"); barraMenus.add(menu1); menu1.add(infoAction); MenuManager menu2 = new MenuManager("Más ayuda"); barraMenus.add(menu2); menu2.add(infoAction); return barraMenus; } protected ToolBarManager createToolBarManager(int estilo) { return new ToolBarManager(estilo); } // Como no se ha reescrito el método canHandleShellCloseEvent(), // se llamará a este método cuando se intente cerrar la ventana. protected void handleShellCloseEvent() { String tipo[] = {IDialogConstants.CANCEL_LABEL, IDialogConstants.OK_LABEL}; MessageDialog dialogo = new MessageDialog( getShell(), "Adiós", null , "¿Desea cerrar la aplicación?", MessageDialog.WARNING, tipo, 0); if (dialogo.open() == 1) { // respuesta: OK close(); } } }

import org.eclipse.jface.window.*; import org.eclipse.jface.action.*; import org.eclipse.jface.dialogs.*; //necesaria para el MessageDialog de JFace /** * Esta clase muestra extiende la clase Action y define un comportamiento * común (mostrar un mensaje de información) para los menús de la * clase EjemploAction. Se utiliza la clase MessageDialog de JFace. * */

Ejemplo 33b: InformacionAction.java

Page 97: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 97 de 114

public class InformacionAction extends Action { private ApplicationWindow ventana; public InformacionAction(ApplicationWindow aw) { ventana = aw; setText("Información"); } public void run() { String[] tipo = {IDialogConstants.OK_LABEL}; MessageDialog dialog = new MessageDialog(ventana.getShell(), "Se ha lanzado la acción", null , "Mensaje de información", MessageDialog.INFORMATION, tipo, 0); dialog.open(); } }

Figura 60. Resultado de ejecutar la clase EjemploAc tion

Page 98: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 98 de 114

A menudo, los programadores trabajan con datos que proceden de fuentes

distintas. Independientemente de la procedencia de los datos, éstos suelen mostrarse de maneras bien distintas: mediante listas, tablas, árboles, etc. Para mostrar los datos, hay ciertos pasos que suelen ser siempre los mismos: obtener los datos (de una base de datos, de un archivo de texto, de una colección), mostrarlos en un cierto orden (alfabético, por caso), asociarlos a cadenas de texto, ocultar algunos y buscar otros...

Tal como se adelantó al principio de este apartado, JFace proporciona un mecanismo para trabajar rápidamente con pasos como los anteriores: el componente Viewer (visor), compuesto por la clase Viewer y sus subclases e interfaces relacionadas. Dicho componente se basa en la arquitectura Modelo-Vista-Controlador, en la que se basan Swing y JFace.

La arquitectura MVC separa los objetos del dominio (el modelo) de la interfaz de

usuario (la vista) y de la lógica que los controla (el controlador). Consideremos, por ejemplo, un componente de tipo lista. Su modelo son los datos; la vista es la representación en pantalla de la lista; por último, el controlador es la parte del componente que gestiona la interacción con el usuario (pulsación de teclas, del ratón, etc.). Usando juiciosamente esta arquitectura, un mismo modelo se puede mostrar mediante muchas vistas: por ejemplo, una serie de datos se puede mostrar como un gráfico circular, como una curva o como una tabla.

En la arquitectura MVC más general posible, el modelo se encarga de acceder a la capa de almacenamiento de datos, especifica las reglas de negocio (una cuenta no debe tener un saldo negativo, por ejemplo), controla las vistas y los controladores y notifica a las vistas los cambios de los datos. El controlador se encarga de gestionar los sucesos de entrada (verbigracia, si el usuario apretara un botón “Aceptar”, el controlador llamaría al método actualizar() de la vista y al método actualizarSaldo() del modelo). La vista, en fin, se encarga de recibir los datos del modelo y de mostrarlos al usuario; para ello, conserva un registro del controlador al que está vinculado y suele tener algún método de actualización que puede ser llamado por el controlador o por el modelo.

En la figura 62 se muestra cómo procesa la arquitectura MVC los sucesos de los

usuarios:

1) El usuario genera un suceso.

2) El controlador recibe el suceso y lo transforma en una petición al modelo.

3) El modelo se actualiza y avisa a la vista de que debe actualizarse.

4) La vista pide datos al modelo para poder actualizarse; luego, actualiza la representación de los datos.

5) El controlador retoma el control.

Page 99: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 99 de 114

Figura 61. Representación estática de la arquitectu ra MVC. Dibujo de Juan Carlos Dueñas López

Page 100: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 100 de 114

Figura 62. Representación dinámica de la arquitectu ra MVC. Dibujo de Juan

Carlos Dueñas López En el caso concreto de JFace, una clase Viewer (visor) corresponde a la parte de la

vista y se encarga de presentar una interfaz más simple que la del widget que debe mostrar los datos. Entre los métodos más usados de la interfaz se encuentran los que sirven para añadir o eliminar elementos de la colección de datos mostrados por el widget.

De manera general, los visores (viewers) tienen asociados proveedores de contenidos (content providers) y proveedores de etiquetas (label providers). Cuando un visor recibe un suceso, pregunta al visor qué debe hacer, es decir, qué elemento o elementos debe mostrar u ocultar. En una estructura de datos como un árbol, el proveedor de contenidos almacena la información sobre el hijo o el padre de cada

Page 101: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 101 de 114

elemento almacenado en la estructura. Asimismo, mediante llamadas a métodos de tipo refresh(), update(), add() y remove(), el proveedor de contenidos avisa al visor de los cambios en el modelo. Los proveedores de etiquetas son utilizados por los visores para averiguar qué texto y qué imagen deben asociarse a cada elemento del modelo.

Los widgets de tipo Table, List, Tree, etc., tienen asociados subclases de Viewer (TableViewer, ListViewer, TreeViewer, TableTreeViewer, TextViewer, CheckboxTreeViewer, CheckboxTableViewer), por medio de las cuales se manipulan los datos. En las siguientes páginas se muestran dos ejemplos de uso de la clase ListViewer. En uno no se usan explícitamente proveedores de contenido ni de etiquetas; en el otro sí.

import org.eclipse.jface.viewers.*; import org.eclipse.jface.window.*; import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; /* * Esta clase utiliza un visor ListViewer para controlar los elementos * de una lista. Si se hace doble clic sobre un elemento, éste se muestra por * consola. * * Las subclases de Viewer (ListViewer, TreeViewer, TableViewer...) permiten * trabajar con objetos de un dominio (elementos) y mostrarlos como widgets * SWT, sin que el programador tenga que preocuparse de pasar del elemento * al widget, ni viceversa, ni de mantenerlos sincronizados. * */ public class EjemploViewer extends ApplicationWindow { private ListViewer visor; public EjemploViewer() { super (null ); } public static void main(String args[]) { EjemploViewer ventana = new EjemploViewer(); ventana.setBlockOnOpen(true ); ventana.open(); Display.getCurrent().dispose(); } protected Control createContents(Composite padre) { visor = new ListViewer(padre, SWT.SINGLE); // Se crean los objetos del dominio. int i = 1; while (i <= 10) {

Ejemplo 34: EjemploViewer.java

Page 102: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 102 de 114

visor.add(new ElementoLista(i)); i++; } // Si se hace doble clic en un elemento de la lista, se // muestra el elemento por consola. visor.addDoubleClickListener( new IDoubleClickListener() { public void doubleClick(DoubleClickEvent e) { IStructuredSelection selection = (IStructuredSelection) e.getSelection(); System.out.println("Ha hecho clic en " + selection.getFirstElement().toString()); } }); return visor.getList(); } } // Clase que define el modelo de objetos. class ElementoLista { private String texto; public ElementoLista(int i) { texto = "Elemento número " + i; } public String toString() { return texto; } }

Figura 63. Resultado de ejecutar la clase EjemploVi ewer

Page 103: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 103 de 114

import org.eclipse.jface.window.*; import org.eclipse.swt.widgets.*; import org.eclipse.jface.viewers.*; import org.eclipse.swt.*; import org.eclipse.swt.layout.*; /* * Esta clase utiliza Nota, ListaNotas, ListaNotasContentProvider y * ListaNotasLabelProvider para manipular una lista de notas. Al * seleccionar el nombre de un alumno, se muestra por consola su * nota. * */ public class EjemploViewer2 extends ApplicationWindow { public EjemploViewer2() { super(null); } public static void main(String[] args) { EjemploViewer2 ventana = new EjemploViewer2(); ventana.setBlockOnOpen(true); ventana.open(); Display.getCurrent().dispose(); } public Control createContents(Composite padre) { getShell().setText("Lista de notas de Ampliación de Mecánica Cuántica"); Composite composite = new Composite(padre, SWT.NONE); FillLayout layout = new FillLayout(SWT.HORIZONTAL); composite.setLayout(layout); Label etiqueta= new Label(padre, SWT.CENTER); etiqueta.setText("Saludos con JFace"); ListViewer visorLista = new ListViewer(composite, SWT.H_SCROLL); visorLista.setContentProvider(new ListaNotasContentProvider()); visorLista.setInput(new ListaNotas()); visorLista.setLabelProvider(new ListaNotasLabelProvider()); // Gestión de sucesos. Al seleccionarse un alumno, se muestra // por consola su nota. visorLista.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent e) { IStructuredSelection selection = (IStructuredSelection) e.getSelection(); Nota nota = (Nota) selection.getFirstElement(); System.out.println(nota.getNombreAlumno()); } }); return composite;

Ejemplo 35a: EjemploViewer2.java

Page 104: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 104 de 114

} }

/** * Esta clase es el modelo de objetos del ejemplo número 35. * Cada objeto Nota representa la nota de un alumno de la * asignatura Ampliación de Mecánica Cuántica. * */ public class Nota { private String nombreAlumno; private double calificacion; public Nota(String nombreAlumno, double calificacion) { this.nombreAlumno = nombreAlumno; this.calificacion = calificacion; } // Métodos get public String getNombreAlumno() { return nombreAlumno; } public String getCalificacion() { return Double.toString(calificacion); } }

import java.util.*; /** * Esta clase define una lista de objetos Nota. * */ public class ListaNotas { private List listaNotas = new ArrayList(8); public ListaNotas() { rellenarLista(); } private void rellenarLista() {

Ejemplo 35b: Nota.java

Ejemplo 35c: ListaNotas.java

Page 105: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 105 de 114

listaNotas.add(new Nota("Luis Rodrigo", 6.7)); listaNotas.add(new Nota("José Ángel Marín", 7.1)); listaNotas.add(new Nota("Gustavo Poler", 9.3)); listaNotas.add(new Nota("José Luis Albiach", 7.8)); listaNotas.add(new Nota("Fedérico Monsálvez", 6.2)); listaNotas.add(new Nota("Donal Piddington", 9.2)); listaNotas.add(new Nota("Rosa Pérez", 6.9)); listaNotas.add(new Nota("Rosa Igual", 7.5)); } public Object[] getListaNotas() { return listaNotas.toArray(); } }

import org.eclipse.jface.viewers.*; /** * Esta clase actúa como proveedor de contenidos. Para ello, implementa * IStructuredContentProvider, interfaz que debe implementar cualquier * proveedor de contenidos que medie entre el visor y su modelo. * */ public class ListaNotasContentProvider implements IStructuredContentProvider { // Este método devuelve los elementos que deben mostrarse en el visor // cuando su entrada se establece a un elemento. public Object[] getElements(Object elementoEntrada) { return ((ListaNotas) elementoEntrada).getListaNotas(); } // Este método notifica al proveedor de contenido que la entrada del usuario ha // cambiado de un objeto a otro. // En este ejemplo no es necesario implementarlo. public void inputChanged(Viewer visor, Object objetoAntiguo, Object objetoNuevo) { } // Libera los contenidos del proveedor de contenidos. Cuando se llama al método // dispose() del visor, éste llama a este método. // En este ejemplo no es necesario implementarlo. public void dispose() { } }

Ejemplo 35d: ListaNotasContentProvider.java

Page 106: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 106 de 114

import org.eclipse.jface.viewers.*; import org.eclipse.swt.graphics.*; /** * Esta clase actúa como proveedor de etiquetas. Para ello, implementa * ILabelProvider, interfaz usada por muchos visores (excepto TableViewer), y * extiende la clase LabelProvider, que es una implementación por omisión de * ILabelProvider y que usa un String para el texto de cada elemento, y * null para cada imagen. * */ public class ListaNotasLabelProvider extends LabelProvider implements ILabelProvider { // Devuelve un String para el elemento. public String getText(Object elemento) { return ((Nota) elemento).getNombreAlumno(); } // En general, devuelve una imagen para el elemento. // En este ejemplo, no devuelve ninguna (null). public Image getImage(Object elemento) { return null; } }

Figura 64. Resultado de ejecutar la clase EjemploVi ewer2

Ejemplo 35e: ListaNotasLabelProvider.java

Page 107: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 107 de 114

En el siguiente ejemplo se muestra cómo trabajar con asistentes (wizards).

import org.eclipse.swt.widgets.*; import org.eclipse.jface.wizard.WizardDialog; /** * Esta clase muestra un asistente que permite elegir la página a la que * se quiere ir (página 1, 2 o 3). Para ello, usa las clases PaginaSeleccion, * AsistentePagina, Pagina1, Pagina2 y Pagina3. * */ public class EjemploWizard { public static void main(String[] args) { Display display = new Display(); Shell shell = new Shell(display); // Se crea el diálogo de asistente y se muestra. WizardDialog dialogoAsistente = new WizardDialog(shell, new AsistentePagina()); dialogoAsistente.open(); display.dispose(); } }

import org.eclipse.jface.wizard.Wizard; /** * Esta clase especifica las páginas contenidadas en el asistente y su comportamiento * cuando se pulsa el botón Finish (Finalizar) del asistente. * */ public class AsistentePagina extends Wizard { public AsistentePagina() { // Se añaden las páginas. addPage(new PaginaSeleccion()); addPage(new Pagina1()); addPage(new Pagina2()); addPage(new Pagina3()); } // Respuesta cuando el usuario aprieta el botón Finish public boolean performFinish() { System.out.println("Se sale del asistente"); return true ; // true indica que se cierra el asistente

Ejemplo 36a: EjemploWizard.java

Ejemplo 36b: AsistentePagina.java

Page 108: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 108 de 114

} }

import org.eclipse.swt.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.WizardPage; /** * Esta clase representa la página que permite al usuario elegir a qué página * desea ir. Es una subclase de WizardPage. */ public class PaginaSeleccion extends WizardPage { private Button pagina1; private Button pagina2; private Button pagina3; public PaginaSeleccion() { super("Página de selección "); } // Se crean los controles de la página. public void createControl(Composite padre) { Composite compo1 = new Composite(padre, SWT.NONE); compo1.setLayout(new GridLayout(3, true)); Composite compo2 = new Composite(compo1, SWT.NONE); compo2.setLayout(new FillLayout(SWT.VERTICAL)); Label etiqueta = new Label(compo1, SWT.LEFT); etiqueta.setText("¿A qué página desea desplazarse?"); pagina1 = new Button(compo2, SWT.RADIO); pagina1.setText("Página 1"); pagina2 = new Button(compo2, SWT.RADIO); pagina2.setText("Página 2"); pagina3 = new Button(compo2, SWT.RADIO); pagina3.setText("Página 3"); setControl(compo1); }

Ejemplo 36c: PaginaSeleccion.java

Page 109: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 109 de 114

// Se implementa el método getNextPage() de la interfaz IWizardPage, // La clase WizardPage proporciona una implementación general de esta interfaz, pero // se implementa la interfaz directamente porque esa implementación no basta para la lógica // de la aplicación. public IWizardPage getNextPage() { if (pagina1.getSelection()) { return getWizard().getPage("Página 1"); } if (pagina2.getSelection()) { return getWizard().getPage("Página 2"); } if (pagina3.getSelection()) { return getWizard().getPage("Página 3"); } // Por omisión, se va a la primera página. return getWizard().getPage("Página 1"); } }

import org.eclipse.swt.widgets.*; import org.eclipse.swt.graphics.*; // incluye la clase Color import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; /** * Esta clase representa la página 1. Es una subclase de * WizardPage. * */ public class Pagina1 extends WizardPage { public Pagina1() { super("Página 1"); } // Se crean los controles para la página. public void createControl(Composite padre) { Label etiqueta = new Label(padre, SWT.CENTER); etiqueta.setText("Está en la página 1"); etiqueta.setForeground(new Color(null, 15, 134, 250)); etiqueta.setBackground(new Color(null, 100, 14, 50)); setControl(etiqueta); } }

Ejemplo 36d: Pagina1.java

Page 110: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 110 de 114

import org.eclipse.swt.graphics.*; // incluye la clase Color import org.eclipse.swt.widgets.*; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; /** * Esta clase representa la página 2. Es una subclase de * WizardPage. * */ public class Pagina2 extends WizardPage { public Pagina2() { super("Página 2"); } // Se crean los controles para la página. public void createControl(Composite padre) { Text cuadroTexto = new Text(padre, SWT.CENTER| SWT.BORDER | SWT.READ_ONLY); cuadroTexto.setText("Está en la página 2"); cuadroTexto.setForeground(new Color(null, 237, 14, 50)); cuadroTexto.setBackground(new Color(null, 15, 14, 50)); setControl(cuadroTexto); } }

import org.eclipse.swt.widgets.*; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; /** * Esta clase representa la página 3. Es una subclase de * WizardPage. * */ public class Pagina3 extends WizardPage { public Pagina3() { super("Página 3"); } // Se crean los controles para la página public void createControl(Composite padre) { Button boton= new Button(padre, SWT.CENTER | SWT.BORDER );

Ejemplo 36e: Pagina2.java

Ejemplo 36f: Pagina3.java

Page 111: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 111 de 114

boton.setText("Está en la página 3"); setControl(boton); } }

Figura 65. Resultado de ejecutar la clase EjemploWi zard

Page 112: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 112 de 114

Figura 66. Pantalla que aparece cuando se escoge en el asistente la página 2

Cuando se desea usar objetos Color, Font o Image de manera que su ciclo de vida esté asociado al widget que los utiliza, se pueden usar las clases ColorRegistry, FontRegistry e ImageRegistry, respectivamente. Así se evita tener que liberar explicítamente los objetos Color, Font e Image innecesarios.

ColorRegistry, FontRegistry e ImageRegistry permiten también almacenar permanentemente colores, tipos de letra e imágenes, de modo que puedan ser compartidas por distintos widgets o accedidas frecuentemente. El uso típico de estas clases se muestra en este ejemplo:

... String IMAGEN_1 = "imagen1"; // Se crea un descriptor de la imagen y su registro. ImageRegistry ir = new ImageRegistry(); ImageDescriptor id = ImageDescriptor.createFromFile(...); registry.put(IMAGEN_1, id); // Se crea la imagen y se asocia al registro. // Si se destruye el display asociado al shell, se // destruye la imagen. Label etiqueta = new Label(shell, SWT.CENTER); Image imagen = ir.get(IMAGEN_1); etiqueta.setImage(imagen);

Page 113: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

http://www.javahispano.org

© Miguel Ángel Abián, 2005-2014 Página 113 de 114

Como el lector habrá podido apreciar, JFace abastece al desarrollador de una serie de clases que simplifican más que SWT la construcción de interfaces gráficas. Para la mayor parte de los usos, se puede usar JFace directamente.

Con JFace no terminan las posibilidades de Eclipse: la plataforma de clientes ricos de Eclipse (Rich Cliente Platform o RCP) permite construir muy rápidamente workbenches (bancos de trabajo) de Eclipse y compilarlos en aplicaciones que pueden ejecutarse sin Eclipse. Un cliente rico es aquel cliente que aprovecha las posibilidades del sistema operativo donde se ejecuta. El programador puede usar la RCP para construir el armazón gráfico de sus propias aplicaciones, con la ventaja añadida de disponer de una interfaz gráfica impactante, moderna y profesional: la del propio Eclipse.

En la figura 67 se muestra una aplicación, construida con la RCP de Eclipse, que permite seguir en directo las cotizaciones bursátiles.

Figura 67. Captura de pantalla extraída de http://eclipse.org/rcp/ Glosar todas funciones de la RCP y ejemplificarlas cae, por mucho, fuera de los

propósitos de esta serie de artículos, pues hay muchísimas cosas más que contar. Al lector interesado en saber qué partido puede sacarle a la RCP de Eclipse le recomiendo que le eche un vistazo a JLibrary (http://jlibrary.javahispano.net/es/index.html), obra de Martín Pérez. Poco de favoritismo hay en mi recomendación: JLibrary es una aplicación bien útil, usa con maestría casi todas las funciones relevantes de la RCP y está en español. En definitiva: miel sobre hojuelas. Si no incluyo ninguna captura de pantalla es por timidez, no vaya a ser que escoja una poco agraciada y luego me caiga encima alguna lluvia de bien merecidos reproches...

Page 114: Artículo 4 sobre la plataforma ECLIPSE. Especial SWT

El archipiélago Eclipse (parte 4 de 4)

© Miguel Ángel Abián, 2005-2014 Página 114 de 114

In memoriam: Este artículo está dedicado a la memoria de Josefa Jiménez Melendo (Portillo de Soria, 1917-Valencia, 2005). S e fue en enero, cuando el cierzo más azota los pueblos de su Castilla natal, esa Castilla cada vez más olvidada y empobrecida, cada vez más transformada e n coto de caza y en residencia geriátrica. En paz descanse.

Sobre el autor:

Miguel Ángel Abián nació en Soria. Obtuvo la suficiencia investigadora en el Dpto. de Física Aplicada de la Universidad de Valencia con una tesina sobre electromagnetismo. Realizó varios cursos de doctorado relacionados con electromagnetismo, electrónica, semiconductores y cristales fotónicos. Ha recibido becas del IMPIVA (Instituto de la Mediana y Pequeña Industria Valenciana) y de la Universidad Politécnica de Valencia. Cursó un Máster estadounidense en UML y Java y otro sobre tecnologías de Internet/Intranet.

Se incorporó en 1998 a AIDIMA, donde ha participado como investigador en 23 proyectos de investigación nacionales e internacionales relacionados con la Web semántica, tecnologías de la información, madera en construcción, biosensórica, bioelectrónica, telecomunicaciones, visión artificial; así como en la Red de Excelencia de la Comisión Europea INTEROP 2003-2007. Algunos de los proyectos europeos relacionados con las tecnologías semánticas en los que ha participado son ATHENA y STASIS (http://www.stasis-project.net/).

El año 2006 estuvo cuatro meses como investigador invitado en el departamento Lehrstuhl für Messsystem und Sensortechnik de la Universidad Politécnica de Munich (TUM), donde colaboró en el desarrollo de nuevos métodos para la detección de defectos en superficies acabadas y en el diseño e implementación de sistemas distribuidos de sensores para el sector del automóvil y de energías renovables. En 2007 recibió un premio BANCAJA-UPV por un proyecto relacionado con la calidad interna de la madera. En 2009 recibió el premio internacional Schweighofer Innovation Prize -el premio más prestigioso en el sector forestal y de la madera- por su aportación al desarrollo de nuevas tecnologías de evaluación no destructiva de la madera en construcción.

Actualmente es Responsable del Departamento de Tecnología y Biotecnología de la Madera y del Área de Construcción de Madera.

Es coautor de 7 libros y guías técnicas relacionadas con el uso de la madera en la construcción y la visión artificial. También ha publicado varios artículos científicos en revistas como IEEE Transactions on Microwave Theory and Techniques y Wood Science and Technology. Ha participado como ponente en congresos y conferencias como European Congress on Computational Methods in Applied Sciences and Engineering, IEEE International Conference on Multisensor Fusion and Integration for Intelligent Systems, International Conference on Space Structures (IABSE-IASS) y en reuniones COST (European Cooperation in Science and Technology). Ha publicado más de 24 artículos técnicos en revistas sectoriales y técnicas.

Es autor o coautor de 8 patentes, algunas de ellas en trámite. Cuatro de ellas corresponden a dispositivos y métodos para detectar la biodegradación de la madera en construcción.

Actualmente, entre otros proyectos como WOODTECH, SHBUILDINGS, WOODRUB o CELLUWOOD, ha trabajado en SEMCONCEPT, un proyecto de I+D+i para aplicar tecnologías semánticas (ontologías, buscadores semánticos) en el diseño conceptual de productos industriales.

Sus intereses actuales son la evolución de la programación orientada a objetos, Java, la Web semántica y sus tecnologías, la arquitectura orgánica, el surrealismo y París, siempre París.