Artículo 4 ECLIPSE y JAVA

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

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ánPublicado originalmente en javaHispano.

Transcript of Artículo 4 ECLIPSE y JAVA

  • EL ARCHIPILAGO ECLIPSE

    (PARTE 4 DE 4)

    Miguel ngel Abin

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 2 de 114

    EL ARCHIPILAGO ECLIPSE (PARTE 4 DE 4)

    Fecha de ltima revisin: 27.05.2014

    Miguel ngel Abin mabian ARROBA aidima PUNTO es

    Conozco mquinas que son ms 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 ms adecuado que una lengua moribunda. Cuanto ms muerta est una

    lengua, ms 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 haba dejado atrs 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: confusin (musical y personal), pop, rock'n'roll, distorsin, experimentacin (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 coincida 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 informticos: espero que nunca le muerda). Nadie le impide agregar a Eclipse los plug-ins (extensiones) que desee y trabajar con un magnfico IDE, hecho a medida, para ASP, JSP, XML, XHTML o HTML. Es ms, 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 estn trabajando mucho y muy bien, con metas muy claras. Con todo, hay mucho de experimentacin, en este caso informtica y comercial, dentro y alrededor de Eclipse.

    Copyright (c) 2005-2014, Miguel ngel Abin. Este documento puede ser distribuido slo bajo los trminos y condiciones de la licencia de Documentacin de javaHispano v1.0 o posterior (la ltima versin se encuentra en http://www.javahispano.org/licencias/).

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 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 haban tenido cuando estaban unidos.

    John Lennon dijo en 1980, poco antes de morir: Si los aos sesenta o los Beatles tenan un mensaje, era aprender a nadar. Y una vez has aprendido, nadar. Esta serie de artculos es una rpida leccin de natacin, impartida con un solo fin: invitarle, si no lo ha hecho ya, a zambullirse en las aguas del ocano Eclipse. No tiene nada que perder, y s mucho que ganar.

    14. SWT: el nuevo componente grfico 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 explicarn en la prxima parte de esta serie de artculos). De acuerdo con la documentacin oficial de Eclipse, he aqu la descripcin del componente Standard Widget Toolkit: "El componente SWT est diseado 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, tambin oficial: [SWT es] un conjunto de componentes grficos y una biblioteca grfica integrada con el sistema de ventanas especfico 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 todava no existe; una traduccin aproximada sera cachivache o trasto. Chocara mucho leer frases como el cachivache pequeo se coloca en el centro del cachivache grande en un artculo tcnico en espaol; en cambio, en ingls suenan incluso simpticas.

    La documentacin oficial de Eclipse (http://www.eclipse.org) establece que un widget es cualquier objeto de la interfaz grfica de usuario que puede colocarse dentro de otro widget (versin tecnolgica 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 definicin ms aclaratoria: Un widget es un objeto de la interfaz grfica de usuario, responsable de la interaccin con el usuario.

    En la documentacin y la bibliografa de Eclipse suelen usarse de manera intercambiable las palabras widget y control (elemento de la interfaz grfica 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 grfica), pero no controles. La razn para esto es prctica: si el rbol se encarga de dibujar los nodos y subnodos, se evita consumir los recursos del sistema operativo que se necesitaran si cada nodo fuera un control.

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 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 trminos dista mucho de ser unnime, suele aceptarse que peso ligero significa que hay una asociacin 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 programacin grfica: todas las implementaciones de los sucesos (apretar una tecla, mover el ratn...) 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 botn. Cuando el usuario pulse el botn, el suceso ir, primero, de la biblioteca grfica del SO a la mquina virtual de Java; luego, ir a la lgica 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 ratn o apretar una tecla. A cambio, su rendimiento resulta, en general, mejor que el de uno pesado (en cuanto a recursos, es ms 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 grficos, las etiquetas sern 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 milln de filas. En Swing, el tiempo que se tardara en dibujarla apenas diferira del empleado para dibujar una tabla de diez mil filas. En SWT, el tiempo que se tardara en dibujar la tabla de un milln de filas sera de dos rdenes de magnitud superior al necesario para dibujar la tabla de diez mil filas, pues cada fila sera un widget mantenido por el sistema operativo (omito aqu cualquier consideracin sobre la memoria que empleara 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 ms widgets? Por fuera, s; pero por dentro hay muchas diferencias. Tanto AWT como SWT usan las funciones de la API grfica 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 cdigo nativo, escrito en C o C++, que hace llamadas a las bibliotecas grficas 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 cdigo mquina resultante de compilar el cdigo nativo (el cdigo mquina cambia para cada plataforma, pero no las clases Java).

    De resultas del diseo basado en componentes gemelos, AWT tiene un nmero muy limitado de widgets, pues slo 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 estn escritos en Java, no en cdigo nativo; y los mtodos grficos de la plataforma se llaman a travs de una capa que se explicar ms adelante. Para cada plataforma, esta capa expone los mtodos de la API (interfaz de

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 5 de 114

    programacin de aplicaciones) grfica de la plataforma, de suerte que las clases SWT (escritas en Java) pueden llamar a los mtodos de la API grfica. A diferencia de AWT, las clases SWT cambian en cada plataforma. Aparte de que hay muchos ms widgets en SWT que en AWT, la gran ventaja de SWT es que toda la lgica de los widgets est escrita en Java (en AWT, la lgica est mezclada con cdigo nativo de cada plataforma).

    El propsito original de Swing consista 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 cdigo que interacciona directamente con los widgets de cada plataforma est escrito en C o C++ (forma parte de las bibliotecas de AWT especficas de cada plataforma) y, en consecuencia, no est disponible para Swing, que est escrito en Java. Tambin 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 grfica 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 grficas. Cuando se quiere mostrar una interfaz al usuario, Swing a travs de AWT enva 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 electrnicas o telfonos mviles, donde la memoria est muy limitada.

    En cuanto a la personalizacin 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 deberan 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 sensacin de Windows (Windows L&F) que proporciona Swing ha sido (hasta la versin 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 versin del sistema operativo a otro.

    En comparacin 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 mtodos nativos (mtodos propios de la plataforma, generalmente escritos en C o C++) y que reciban los resultados que stos devuelven. Cuando se compila un archivo con cdigo JNI-C (cdigo en C donde se implementan mtodos declarados de tipo JNI), se genera una biblioteca compartida en Windows, una DLL o biblioteca de enlace dinmico, que permite acceder desde Java a los mtodos declarados en el cdigo JNI-C.

    Para ilustrar cmo se trabaja con JNI, considero aqu el ejemplo de un mtodo nativo que calcula nmeros de Fibonacci.

    En primer lugar, el mtodo nativo se declara en una clase llamada MetodoNativo:

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 6 de 114

    public class MetodoNativo {

    // declaracin Java del mtodo 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 consideracin 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 /* 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 implementacin en C del mtodo fibonacci() se guarda en un archivo ImplementacionMetodoNativo.c:

    #include #include MetodoNativo.h

    /* implementacin en C de la funcin que calcula el nesimo nmero de Fibonacci */ int fibonacci(int n) { if (n

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 7 de 114

    return (fibonacci(n-1) + fibonacci(n 2)); }

    /* implementacin 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 mtodo nativo fibonacci() podr usarse desde cualquier clase de Java.

    La tcnica que usa SWT para llamar mediante JNI a las API grficas de cada sistema operativo (escritas en C o C++) consiste en establecer, siempre que sea posible, una correspondencia uno a uno entre los mtodos en Java de cada widget SWT y las llamadas a la API grfica propia de cada sistema operativo. Ms adelante, veremos cdigo 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 integracin con la plataforma. Un widget SWT llama directamente al gestor de ventanas especfico 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 integracin casi completa con cada plataforma. No olvidemos que la integracin con la plataforma no se reduce a la apariencia y la sensacin (L&F): caractersticas como copiar y pegar o arrastrar y soltar son automticas 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, an existen acciones que no producen en algunas plataformas los resultados que esperara el usuario habituado a stas.

    Tal es la integracin de SWT con la plataforma, que refleja inmediatamente los cambios en la apariencia y sensacin 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 sensacin. Una piel o skin es un conjunto de grficos que incluye todas las piezas necesarias para cambiar el aspecto y sensacin de la interfaz grfica. Los grficos pueden incluir imgenes para botones, barras, mens, etc. Skinning es la accin de aplicar una piel. Cuando se aplica una piel a Windows, se altera su apariencia y sensacin: cambian los colores, los botones, etc. (El trmino skinning se us originalmente en el videojuego Quake, juego tremendamente popular por su carcter intimista y conciliador. Para dar variedad al juego se inventaron varias pieles, que permitan al usuario cargar una serie de grficos que cambiaban la apariencia del personaje principal, un pacfico y sosegado ciudadano.)

    La integracin no se detiene en la apariencia y la sensacin de Windows: SWT permite trabajar con los objetos binarios reutilizables de Microsoft (COM). De hecho, con unas pocas llamadas a mtodos SWT se puede incluir controles ActiveX y documentos OLE en las aplicaciones SWT.

    La declaracin del mtodo Java_MetodoNativo_fibonacci() en

    ImplementacionMetodoNativo.c debe coincidir con la del mtodo

    Java_MetodoNativo_fibonacci() en MetodoNativo.h.

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 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 mnimo comn denominador. Por ejemplo, Motif no proporciona por omisin un widget de tipo rbol; consecuentemente, el SWT proporciona un widget rbol con la misma API que la implementacin propia de Windows. Ningn 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 cmo debe comportarse (salvo que provenga de Windows). A diferencia de AWT, SWT proporciona todos los controles que se suponen imprescindibles en cualquier interfaz grfica moderna.

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 9 de 114

    Una vez obtenida la correspondencia uno a uno entre los mtodos en Java y los mtodos propios de la API grfica de la plataforma, el desarrollador puede olvidarse del cdigo JNI-C y de los detalles de bajo nivel del sistema operativo, y limitarse a utilizar los mtodos pblicos 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 caractersticas de los widgets propios de cada plataforma. Acta, en definitiva, como una fina capa entre Java y las bibliotecas de la API grfica especfica de cada SO. En comparacin con Swing, SWT evita el uso de una capa gruesa y ralentizadora como la de AWT (vese la figura 15).

    Casi todo el cdigo 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 informacin sobre los componentes SWT. No hace falta mucho ms: SWT usa, siempre que puede, la informacin que proporciona la API grfica de cada plataforma.

    Cualquier aplicacin escrita en Java podra utilizar la JNI para establecer una correspondencia entre los mtodos Java y las capacidades grficas propias de la plataforma usada. La ventaja de usar SWT radica en que evita a los programadores escribir su propio cdigo 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 componentes grficos

    Componente grfico Swing AWT

    Biblioteca grfica del SO

    Swing

    Componente grfico SWT

    Biblioteca grfica del SO

    JNI-CSWT

    Miguel ngel Abin, marzo de 2005

    escrito en C escrita en Cescrito en Java

    escrito en Java escrita en C

    r

    FUNCIONAMIENTO INTERNO DE SWING y SWT

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 10 de 114

    Para ver cmo funcionan en SWT los mtodos JNI, podemos considerar el mtodo 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 mtodo asigna un men a una ventana. La palabra reservada native indica al compilador de Java dos cosas: a) la implementacin del cdigo no est escrita en Java; b) la implementacin se guarda en un archivo (os.c) que no es el de la clase OS (os.java). En Windows, el cdigo JNI-C correspondiente al mtodo 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 implementacin en Java del mtodo SetMenu() de la clase OS llama a un mtodo del sistema operativo tambin llamado SetMenu(). (Tal como se adelant, hay una relacin uno a uno entre los mtodos de SWT y los mtodos grficos de la plataforma.)

    Cada plataforma con una implementacin del SWT tiene una biblioteca compartida (en Windows, una biblioteca dinmica o DLL) y uno o ms archivos JAR. La biblioteca compartida, especfica de cada plataforma, resulta de compilar el cdigo JNI-C que establece una correspondencia uno a uno entre los mtodos Java y los mtodos de la API grfica propia del SO. En Windows, esta biblioteca contiene, entre otro mucho cdigo, el cdigo mquina resultante de compilar el cdigo JNI-C del mtodo 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 mtodos JNI-C correspondientes (los cuales, a su vez, llaman a los mtodos nativos de la plataforma). Estas clases comunes, por tener las mismas declaraciones de sus mtodos pblicos para todas las plataformas, permiten que el cdigo Java que use SWT se ejecute sin necesidad de cambios en cualquier otra plataforma donde exista una implementacin de SWT. En ese sentido, SWT resulta a la par transportable y especfico de la plataforma, por contradictorio que parezca (en SWT, todas las interfaces directas a la API grfica especfica del SO estn escritas en Java, excepto la de ms bajo nivel). Tal y como dice IBM en su pgina web: Un importante beneficio de usar SWT es que, una vez se desarrolla una interfaz de usuario en Linux, es tambin una interfaz de primera clase cuando se aplica a Windows. Lo inverso tambin es cierto.

    Un ejemplo completo aclarar el porqu del contradictorio carcter 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 ms plataformas).

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 11 de 114

    En Windows, la clase Button tiene el siguiente cdigo (por brevedad, omito todos los comentarios, salvo el de copyright, y algunos de los mtodos):

    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); }

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 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; } }

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 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);

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 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 cdigo (por brevedad, omito todos los comentarios, salvo el de copyright, y algunos de los mtodos):

    /******************************************************************************* * 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 {

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 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);

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 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); }

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 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 cdigo muy distinto del correspondiente a la misma clase en Windows, pero ambas mantienen la misma declaracin es decir, los mismos argumentos y el mismo tipo de retorno para todos los mtodos pblicos. Por ejemplo, el mtodo pblico setText() de Button mantiene la misma declaracin tanto en Solaris como en Windows: public void setText (String string). (Lo mismo sucede en todas las dems plataformas para las que est disponible SWT.)

    En cuanto a la implementacin de los mtodos pblicos, vara completamente de una a otra cada plataforma. En el caso de setText(), se usan en Windows llamadas a mtodos como OS.GetWindowLong(), que llama, a su vez, al mtodo GetWindowLong() de la biblioteca grfica Win32; en Solaris se usan llamadas a mtodos como OS.XmStringParseText(), que llama, a su vez, al mtodo XmStringParseText() de la bibliotecas grfica Motif. Tal como se dijo antes, la clase OS representa el sistema operativo de la plataforma.

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 18 de 114

    Los mtodos que no son pblicos gozan de completa libertad en cuanto a declaracin. Generalmente, no tienen por qu existir en todas las plataformas. Por ejemplo, no hay un mtodo con una declaracin int callWindowProc(int p0, int p1, int p2) en la clase Button de Solaris, mtodo que goza de buena salud en Windows.

    Como ya se adelant hace unas pginas, que los mtodos pblicos de los widgets SWT se declaren igual en todas las plataformas causa que el SWT sea transportable. En el ejemplo de Button, la implementacin de cada mtodo en Solaris no ser transportable a Windows, y viceversa; pero el cdigo Java que utilice los mtodos pblicos 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 botn SWT") har llamadas en Windows y Solaris, a travs de JNI, a mtodos nativos completamente diferentes; pero funcionar en ambas plataformas (dando distintas resultados grficos, claro est). El cdigo Java que llama a SWT no necesita conocer la implementacin de las clases SWT ni el cdigo JNI-C encargado de llamar a la API grfica correspondiente. Ms an: si lo hiciera se incumplira el principio de encapsulado, fundamental en la programacin orientada a objetos.

    Las bibliotecas JNI-SWT deben compilarse para cada plataforma, lo cual crea un archivo con extensin .dll en Windows y otro con extensin .so en Solaris. En la pgina web de Eclipse se puede descargar el cdigo JNI-C de la biblioteca JNI-SWT para cada plataforma, as como el cdigo 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 grficos de SWT widgets, tipos de letra, colores, imgenes 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 mquina virtual de Java y que ya no se utilizan, no liberar recursos del sistema operativo donde se ejecuta la MVJ. Por esto, la liberacin 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 explcitamente al mtodo dispose() del display correspondiente si realmente quiere liberar los recursos de la ventana y de sus controles. En caso contrario, puede suceder que la aplicacin 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 disminucin 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 liberacin de los recursos de todos los controles hijos. Dicho de otro modo: al llamar al mtodo dispose() del padre, se llama a cada mtodo dispose() de los hijos.

    Mtodos como dispose() resultan necesarios cuando se trabaja con componentes grficos o con sockets, pues llaman a mtodos nativos que saben cmo liberar los recursos asociados del sistema operativo. Si desea ms informacin sobre el uso de dispose() con sockets, puede consultar el apartado 3.3 del tutorial java.net y java.nio. Cmo hacer un chat en Java, http://www.javahispano.org/tutorials.item.action?id=7). Esas llamadas a mtodos nativos son inevitables, ya que los componentes grficos de peso pesado y las conexiones de red dependen por completo del SO.

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 19 de 114

    En el caso de los objetos SWT correspondientes a colores (Color), imgenes (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 mtodo dispose() de los componentes donde se usan tales objetos.

    Estas dos caractersticas no se deben a ningn error de diseo. Antes al contrario: responden a un entendimiento cabal de la naturaleza de esos objetos. Si, por ejemplo, las imgenes tuvieran que crearse asociadas a componentes padre (ventanas, botones, listas, mens...), todos los componentes con una misma imagen necesitaran sendas instancias de la clase Image. Esta situacin sera muy incmoda para el programador (quien tendra que escribir la instaciacin una y otra vez) y para el sistema operativo (imaginmoslo como un grun 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 encontraran los restantes componentes? Sin imagen, que ya estara 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 explcitamente llamando a dispose(). En el apartado dedicado a JFace veremos cmo se puede simplificar la liberacin de los recursos que consumen estos objetos.

    Toda la interfaz grfica de Eclipse se basa en SWT. Ahora bien, ello no significa que este componente grfico se pueda usar slo con Eclipse: las bibliotecas SWT se pueden descargar independientemente de Eclipse y pueden usarse para construir aplicaciones independientes. En la ltima versin de Eclipse (3.0.2), lanzada el 11 de marzo de 2005 (la versin 3.1M5a, an no definitiva, sali en febrero de este ao), 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 artculo de esta serie: http://www.javahispano.org/articles.article.action?id=75), cualquier programador puede usar este componente sin pagar regalas. Para ello, debe configurar el CLASSPATH de su aplicacin 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

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 20 de 114

    todo el cdigo 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 accin: Eclipse en Linux-Motif. Extrado de la documentacin oficial de Eclipse.

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 21 de 114

    Fig. 17. SWT en accin: Eclipse en Linux/Gnome2

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 22 de 114

    Fig. 18. SWT en accin: Eclipse en Windows XP

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 23 de 114

    Fig. 19. SWT en accin: Eclipse en Mac OS X

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 24 de 114

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

    Esta seccin no pretende, ni mucho menos, ser una introduccin completa a SWT. Sus objetivos son mucho ms modestos: explicar qu se necesita para programar con este componente grfico, presentar algunos aspectos de su uso y dar unos cuantos ejemplos representativos de cmo se usan los widgets SWT. Dar una explicacin completa del funcionamiento de SWT queda fuera de las metas de esta serie de artculos (definidas en el primero, http://www.javahispano.org/articles.article.action?id=75).

    Usando SWT, el tpico programa HolaMundo quedara 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 tamao y el texto del shell. shell.setSize(250, 120); shell.setText("Mi primera aplicacin 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 ningn suceso que tratar, el mtodo 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 explcitamente 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 liberarn los recursos asociados; pero es una buena prctica acostumbrarse // a hacerlo.

    Ejemplo 1: Saludos.java

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 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 dnde est el cdigo Java de SWT; es decir, dnde se encuentran las clases SWT. stas se almacenan en el archivo swt.jar. Para indicar a Eclipse dnde 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 botn derecho del ratn (vase la figura 20). A continuacin, hay que seleccionar la opcin Properties. En la ventana que aparece debe seleccionarse Java Build Path (panel de la derecha) y la pestaa Libraries (vase la figura 21). Acto seguido, debe incluirse swt.jar con el botn Add External JARs... (vase la figura 22).

    Segn el FAQ ms 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 versin de SWT que se use, cambiar el nmero separado por puntos que aparece en las rutas (en vez de 3.0.1, podra ser 3.1.0, por ejemplo).

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 26 de 114

    Figura 20. Ntese que la vista que se usa es la de paquetes

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 27 de 114

    Figura 21. Hay que apretar el botn Add External JARs...

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

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 28 de 114

    El segundo paso que se requiere para ejecutar el programa consiste en indicar a Eclipse dnde est la biblioteca compartida que requiere swt.jar. Una manera consiste en introducir, cuando se arranca la mquina virtual de Java, la ubicacin de la biblioteca compartida como argumento de ejecucin. Para ello, basta elegir el men Run, escoger Run... (vase la figura 23), elegir la pestaa Arguments en la parte derecha de la pantalla e introducir en el rea de texto VM arguments lo siguiente (vase la figura 24a):

    -Djava.library.path=

    Tal y como suceda con swt.jar, la biblioteca se encontrar en una ubicacin dependiente de la plataforma. Segn el FAQ de Eclipse, las ubicaciones sern 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...

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 29 de 114

    Figura 24a. La versin de Eclipse de la captura de pantalla es la 3.1M4

    El nombre exacto de la biblioteca JNISWT vara en cada versin de Eclipse (a veces, tambin vara con la plataforma, aunque no vare la versin). En la versin 3.1M3 de Eclipse para Windows 98/ME/2000/XP, el nombre de la biblioteca es swt-win-32-3111.dll (vase la figura 24b).

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

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 30 de 114

    Completados todos los pasos anteriores, la ejecucin 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 ejecucin la clase Saludos, la ventana cambia de aspecto cuando se cambia el estilo de Windows XP por el clsico de Windows.

    Como ya se seal en el apartado anterior, para desarrollar o ejecutar aplicaciones SWT no se necesita el entorno de desarrollo Eclipse. Para ejecutar en Windows una aplicacin SWT sin Eclipse, hay que aadir el archivo swt.jar al CLASSPATH e incluir la biblioteca dinmica 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 estn en C:\SWT, la siguiente orden compilar la aplicacin Saludos desde la lnea de rdenes:

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

    La siguiente orden ejecutar Saludos desde la lnea 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.

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 31 de 114

    La clase Saludos, si bien muy simple, alberga la estructura de cualquier aplicacin SWT:

    1) Se crea un objeto Display.

    2) Se crea un objeto Shell que sirve como ventana principal de la aplicacin.

    3) Se crean dentro del shell los widgets (componentes grficos) que se deseen.

    4) Se configuran los tamaos de los widgets (normalmente, en este paso se registran los sucesos a los cuales atendern 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) acta como puente entre el SWT y las operaciones del sistema de interfaz grfica de la plataforma. Segn la documentacin de esta clase, su principal funcin es implementar el bucle de sucesos de SWT mediante el modelo de sucesos de la plataforma. Adems, proporciona mtodos para acceder a informacin 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 mtodo dispose() se encarga de liberar los recursos que el display consuma del sistema de ventanas especfico de la plataforma (memoria, punteros). Al llamarlo, se eliminan todos los shells que tena 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 tamao de una ventana, SWT pasa el tratamiento de estas acciones a la API grfica del SO. Esta clase tiene varios constructores que admiten como argumento un objeto shell: con ellos se pueden generan shells de dilogo o secundarios (shell significa cscara).

    El mtodo dispose() de esta clase acta de forma similar al mtodo homnimo de la clase Display.

    Nota: La manera ms sencilla de evitar la configuracin del CLASSPATH y del argumento -Djava.library.path desde la lnea 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.

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 32 de 114

    Si comparamos SWT con Swing, los componentes de Swing seran 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 estn definidos en la clase org.eclipse.swt.SWT. Una vez se asigna un estilo a un widget, aqul 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 mensaje de dilogo

    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 botn redondo, de flecha, etc.: todos son instancias de Button.

    - Label. Una etiqueta muestra una cadena de texto, una imagen o una lnea vertical u horizontal separadora.

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

    - Slider. Control que representa un intervalo de valores numricos.

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

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 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 mltiple) elementos de una lista de cadenas de texto.

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

    - Group. Control formado a partir de un Composite con ttulo y borde.

    - Canvas. Control que permite operaciones grficas de todo tipo (dibujar un octgono 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 disear 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 jerrquica de elementos.

    - TreeItem. Objeto que representa una jerarqua de objetos en un control Tree.

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 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 aade una clase Listener mediante un mtodo del estilo addXXXListener(), cuyo argumento es la clase que implementa la correspondiente interfaz de tipo Listener. Asimismo, existen clases adaptadoras clases que implementan por omisin las interfaces Listener, de manera que el programador necesite escribir slo el cdigo de los sucesos que verdaderamente le interesan.

    Plataforma

    Display Shell

    Composite

    Widget

    Widget

    Widget

    Widget

    Bibliotecas

    grficas

    JNI

    FUNCIONAMIENTO INTERNO DEL COMPONENTE SWT

    Miguel ngel Abin, 2005

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 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 accin del usuario (pulsar una tecla, mover el ratn...).

    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 aadir una clase Listener a un control se usan mtodos del estilo addXXXListener().

    5) Las clases Adapters (adaptadoras) son clases que implementan las interfaces Listener con una implementacin por omisin para cada mtodo. En vez de una clase Listener, el programador puede asociar un Adapter a un componente, de manera que slo tenga que implementar los mtodos que necesite. Por ejemplo, a la interfaz FocusListener le corresponde la clase adaptadora FocusAdapter.

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 36 de 114

    Figura 28. Tabla con los sucesos y las clases Listener ms importantes

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 37 de 114

    He aqu un ejemplo de cdigo 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 botn 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 botn con borde. * CHECK crea un botn de casilla de verificacin. * PUSH crea un botn estndar (valor por omisin). * RADIO crea un botn de opcin. * TOGGLE crea un botn que mantiene su estado pulsado o no pulsado. * FLAT crea un botn sin efectos de relieve 3D (plano). * ARROW crea un botn en forma de flecha (UP y DOWN marcan el sentido de sta). * LEFT, RIGHT, CENTER alinean el texto asociado al botn. */

    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 tamao y el texto del shell. shell.setSize(250, 120); shell.setText("Ventana hecha con el SWT");

    // Se establece el tipo, eltamao y el texto del botn. // Un botn 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 botn de tipo TOGGLE");

    // Tratamiento de sucesos: muy similar a como se hace en Swing. // Ntese que hay que implementar todos los mtodos de cada interfaz // Listener. boton.addSelectionListener(new SelectionListener() { public void widgetSelected(SelectionEvent e) { System.out.println("Se ha seleccionado el botn"); } public void widgetDefaultSelected(SelectionEvent e) { System.out.println("Se ha seleccionado el botn");

    Ejemplo 2: EjemploBoton.java

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 38 de 114

    } });

    boton.addMouseListener(new MouseListener() { public void mouseDown(MouseEvent e) { System.out.println("Se ha movido el ratn hacia abajo"); } public void mouseUp(MouseEvent e) { System.out.println("Se ha movido el ratn hacia arriba"); } public void mouseDoubleClick(MouseEvent e) { System.out.println("Se ha hecho doble click en el botn"); } });

    // 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 EjemploBoton

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 39 de 114

    Si en la clase EjemploBoton interesara procesar slo el suceso Selection, sera mucho ms rpido 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 botn"); } });

    El ejemplo anterior quedara 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 tamao y el texto del shell. shell.setSize(250, 120); shell.setText("Ventana hecha con el SWT");

    // Se establece el tipo, el tamao y el texto del botn. Button boton = new Button(shell, SWT.TOGGLE); boton.setSize(150, 50); boton.setText("Soy un botn 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 botn"); } });

    shell.open ();

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

    display.dispose (); }

    Ejemplo 3: EjemploBoton2.java

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 40 de 114

    }

    Con todo, existe una relevante diferencia entre el SWT y Swing: un programa que use SWT y no disponga de algn bucle que se encargue de leer y procesar los sucesos del sistema operativo terminar en cuanto se llegue al final del mtodo main(). Por ejemplo, el usuario slo ver una ventana que se cierra al momento si ejecuta las clases anteriores sin este cdigo (si su mquina es lo bastante rpida, 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 slo se entregan al programa (y, en consecuencia, slo pueden procesarse) cuando se llama a un mtodo SWT. En los ejemplos anteriores, el mtodo readAndDispatch() se encarga de entregar al programa en ejecucin los sucesos generados por el usuario. Sin l, el comportamiento del botn sera anmalo: no respondera a las acciones del usuario (defecto, dicho sea de paso, que los usuarios desprecian).

    A continuacin, 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 mens * Se necesita incluir el paquete org.eclips.swt.graphics.Image * para poder trabajar con imgenes en SWT. *

    * La clase Menu acta 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 mens. * 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

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 41 de 114

    * SEPARATOR. *

    * CHECK crea un men de casilla de verificacin. * CASCADE crea un men en cascada con un submen. * PUSH crea un elemento estndar de men. * RADIO crea un men de opcin. * 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 mens"); 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 EjemploMenu1

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 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 mens que tiene dos mens con submens. * Se necesita incluir el paquete org.eclips.swt.graphics.Image * para poder trabajar con imgenes 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 mens"); shell.setImage(new Image(display, "c:\\Eclipse.jpg"));

    // Se crea la barra de mens. Se pueden crear ms, pero slo 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 mens. Menu menuArchivo = new Menu(shell, SWT.DROP_DOWN); archivo.setMenu(menuArchivo); MenuItem abrir = new MenuItem(menuArchivo, SWT.RADIO); abrir.setText("Abrir");

    // Se aade al men de archivos una lnea separadora. MenuItem separador = new MenuItem(menuArchivo, SWT.SEPARATOR);

    // Se aade 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("Edicin");

    Ejemplo 5: EjemploMenu2.java

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 43 de 114

    // Se crea el men de edicin y se asocia al MenuItem editar de la barra de // mens. Menu menuEditar = new Menu(shell, SWT.DROP_DOWN); editar.setMenu(menuEditar); MenuItem cortar = new MenuItem(menuEditar, SWT.PUSH); cortar.setText("Cortar");

    // Se aade al men de edicin un elemento Copiar. MenuItem copiar = new MenuItem(menuEditar, SWT.PUSH); copiar.setText("Copiar");

    // Se aade al men de edicin un elemento Pegar. MenuItem pegar = new MenuItem(menuEditar, SWT.PUSH); pegar.setText("Pegar");

    // Tratamiento de los sucesos del usuario. Es obligatorio // incluir el mtodo widgetDefaultSelected, aunque est // vaco.

    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 aplicacin } 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();

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 44 de 114

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

    }

    Figura 31. Resultado de ejecutar la clase EjemploMenu2

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 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 multilnea. * Se necesita incluir el paquete org.eclips.swt.graphics.Image * para poder trabajar con imgenes 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 lneas, 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 lnea vertical. * SEPARATOR y HORIZONTAL generan una lnea 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 slo permite una lnea. * MULTI crea un cuadro de texto que admite varias lneas. * 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 lneas, 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

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 46 de 114

    // Se crean los componentes grficos. 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("Contrasea:"); 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 contrasea es: " + contrasenya.getText()); } }; validarUsuario.addListener(SWT.Selection, listener);

    shell.open();

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

    }

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 47 de 114

    Figura 32. Resultado de ejecutar la clase EjemploCuadroTexto1

    import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.*; import org.eclipse.swt.graphics.Image;

    /** * Esta clase genera un cuadro de texto multilnea. * Se necesita incluir el paquete org.eclips.swt.graphics.Image * para poder trabajar con imgenes 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 multlinea. 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

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 48 de 114

    texto.setBounds(10, 10, 200, 28); texto.setText( "Lnea 1" + System.getProperty("line.separator") + "Lnea 2");

    shell.open();

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

    display.dispose(); }

    }

    Figura 33. Resultado de ejecutar la clase EjemploCuadroTexto2

    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

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 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);

    // gestin 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 vaco. 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 vaco."); } } }; // fin focusListener

    texto1.addFocusListener(focusListener); texto2.addFocusListener(focusListener); texto3.addFocusListener(focusListener);

  • El archipilago Eclipse (parte 4 de 4)

    Miguel ngel Abin, 2005-2014 Pgina 50 de 114

    shell.open();

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

    display.dispose(); }

    }

    Figura 34. Resultado de ejecutar la clase EjemploCuadroTexto3

    import org.eclipse.swt.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.*;

    /** * Esta clase muestra cmo 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 lneas, si * resulta necesario. * SHADOW_IN (usado con SEPARATOR) crea un separador que parece empotrado * en la ventana.

    Ejemplo 9: EjemploEtiqueta.java

  • http://www.javahispano.org

    Miguel ngel Abin, 2005-2014 Pgina 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 lnea vertical. * SEPARATOR y HORIZONTAL generan una lnea 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.HORIZ