LWUIT: Una librería gráfica tipo AWT o Swing para J2ME

1
27014

LWUIT: Una librería gráfica tipo AWT o Swing para J2ME

Introducción.

La velocidad con la que aumentan la capacidad de procesamiento de los dispositivos móviles crece de forma vertiginosa.
No es raro tener en el bolsillo dispositivos cuyas características se asemejan a los ordenadores de sobremesa de hace unos cuantos años…

Uno de los puntos débiles que tienen las especificaciones de J2ME, es la pobreza que nos ofrece el API de contrucción de interfaces gráficos.
Bien es sabido que «lo bonito vende», así que si querías hacer una aplicación rubio con ojos azules (como yo), los programadores
tenían que programar sus aplicaciones en base a Canvas, APIs propietarias de cada fabricante o librerías como
las que presentamos en este tutorial pero de pago..

Dicen que una imagen vale más que mil palabras, así que para empezar a hacerte una idea de lo que puedes conseguir
con esta librería, te recomiendo que veas el siguiente video.

Características generales

A continuación te presento algunas de las carácterísticas y o requisitos generales que he visto más interesantes:

  • Licencia de uso libre, incluso en aplicaciones comerciales. (Revisalo no vaya a ser que cambie).
  • Requiere CLDC 1.1 o superior y MIDP 2.0 o superior.
  • API muy fácil comprender, sobre todo si has programado en Swing o AWT.
  • Si se optimiza y/o ofusca el código no es demasiado pesada en el proyecto.
  • Buena documentación.

Características funcionales

  • Amplia la funcionalidad de la mayoría de los controles gráficos estandar ubicados en el paquete javax.microedition.lcdui.
  • Aporta más controles gráficos: ComboBox, ListBox, TabbedPane, Dialog, Calendar.
  • Incorpora casi todos los Layouts: GridLayout, BoxLayout, BorderLayout, etc definidos en AWT.

    Para el que no lo sepa, un Layout sirve para indicar de forma semántica la colocación de los componentes gráficos dentro de su contenedor, de manera que la aplicación es más portable entre distintos tamaños de pantalla.
  • Eventos y Listeners: El programador se registra en los eventos que esté interesado tratar.
  • Posibilidad de incluir y cambiar Temas en tiempo de ejecución, algo similar a especificar la apariencia de los controles mediante CSS en función de su «clase».

    Por ejemplo, todos los controles salen con borde rojo y letra verde.
  • Soporta dispositivos con pantallas sensibles al tacto.
  • Posibilidad de establecer el orden de tabulación entre controles.
  • Más máscaras de entrada para los campos de texto: MAILADDR, URL, etc.
  • Transiciones entre pantallas. Es posible de forma fácil (con 0, 1 ó 2 líneas de código) aplicar efectos en 2D/3D entre la pantalla que se oculta y la que se muestra.
  • Renderer y DataModel, para personalizar la vista y el contenido de botones, listas desplegables, casillas de verificación, etc.

    por ejemplo, que cuando se pulse un botón que se muestre una imágen en su fondo o que al desplegar una lista que se muestren imágenes y texto…
  • Animaciones en 2D/3D.
  • Soporte para internacionalización no basada en el estándar
  • Editor de recursos (temas, mensajes, imágenes, fuentes, etc) que luego serán leídos fácilmente desde la aplicación.
  • Un pequeño framework de gestión de trazas integrado (es decir, mini mini mini Log4J, eso sí muy útil :-))

Un ejemplo

Hacer una aplicación que explique todo se saldría del propósito de este tutorial, así que me voy ha hacer una pequeña aplicación en donde se vean algunas de las funcionalidades y sirva como tirón inicial para el lector.
De todas formas, recuerda que una de las características generales que cite anteriormente es que la documentación es bastante buena.

A continuación os dejo el código fuente para que realices tus pruebas. Código fuente del proyecto (Netbeans).

Aspecto de la aplicación a construir:

Fichero de recursos utilizando la aplicación ResourceEditor que incluye la librería:

Es una aplicación Java que está ubicada en el directorio util de la distribucción oficial.

La clase principal de la aplicación (MIDlet):

package com.autentia.tutoriales;

import javax.microedition.midlet.*;
import com.sun.lwuit.Display;
import com.sun.lwuit.plaf.UIManager;
import com.sun.lwuit.util.Resources;


/**
 * Midlet de ejemplo LWUIT
 * @author Carlos García. Autentia.
 */
public class LWUITDemoMidlet extends MIDlet {
    private Resources resources;

    public void startApp() {
        // Inicializamos la librería LWUIT
        Display.init(this);
        
        try {
            
            //Cargamos el único archivo de recursos de la aplicación
            this.resources = Resources.open("/autentiaTheme.res");
            
            // Cargamos el tema
            UIManager.getInstance().setThemeProps(resources.getTheme("AutentiaTheme1"));

            // Refrescamos para que se vea bien
            Display.getInstance().getCurrent().refreshTheme();
        } catch (Exception ex) {
            // No se dará
        }
        
        MainUI ui = new MainUI(this);
        ui.show();
    }

    /**
     * @return Devuelve una referencia al archivo de recursos
     */
    protected Resources getResources(){
        return this.resources;
    }

    public void destroyApp(boolean unconditional) {
        this.notifyDestroyed();
    }
    public void pauseApp() {}
}

La ventanita del ejemplo

package com.autentia.tutoriales;

import com.sun.lwuit.*;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.events.ActionListener;
import com.sun.lwuit.layouts.*;
import com.sun.lwuit.util.Resources;

/**
 * Ventana principal
 * @author Carlos García. Autentia.
 */
public class MainUI extends Form implements ActionListener {

    private LWUITDemoMidlet midlet;
    private Button          btnExit;

    /**
     * Constructor
     */
    public MainUI(LWUITDemoMidlet midlet){
        super();
        this.midlet = midlet;
        this.createUI();
    }

    /**
     * Crea y configura el interface gráfico
     */
    private void createUI(){
        Resources  resources  = this.midlet.getResources();
        TabbedPane tabbedPane = new TabbedPane();

        // El título de la pantalla
        Image imagen     = resources.getImage("logo");
        Label titlePanel = new Label(imagen);
        titlePanel.setAlignment(CENTER);

        // El contenido centrar de la pantalla
        Container panel1  = new Container();
        panel1.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
        panel1.addComponent(new Label("Label"));
        panel1.addComponent(new CheckBox("Checkbox"));
        panel1.addComponent(new ComboBox(new String[]{"ComboBox1", "ComboBox2"}));
        panel1.addComponent(this.getRadioButtonPanel());

        Container buttonsPanel = new Container();
        btnExit = new Button("Salir");
        buttonsPanel.addComponent(btnExit);


        tabbedPane.addTab("Ficha 1", panel1);
        tabbedPane.addTab("Ficha 2", new Container());
        tabbedPane.addTab("Ficha 3", new Container());

        // Añadimos todos los paneles a la ventana
        Container contentPane = this.getContentPane();
        contentPane.setLayout(new BorderLayout());
        contentPane.addComponent(BorderLayout.NORTH,  titlePanel);
        contentPane.addComponent(BorderLayout.CENTER, tabbedPane);
        contentPane.addComponent(BorderLayout.SOUTH,  buttonsPanel);

        // Configuramos la ventana
        this.setTitle("Ejemplo LWUIT");

        // Configuramos los eventos
        btnExit.addActionListener(this);
    }

    /**
     * Crea un panel con dos radio button que forman parte del mismo grupo
     * A modo didactico lo pongo en otro método para que quede más claro.
     */
    private Container getRadioButtonPanel(){
        Container radioButtonPanel = new Container(new GridLayout(1, 2));

        RadioButton radio1 = new RadioButton("Radio1");
        RadioButton radio2 = new RadioButton("Radio2");
        ButtonGroup group1 = new ButtonGroup();
        group1.add(radio1);
        group1.add(radio2);

        radioButtonPanel.addComponent(radio1);
        radioButtonPanel.addComponent(radio2);

        return radioButtonPanel;
    }

    /**
     * Muestra un cuadro de diálogo
     * @param Texto del cuadro de diálogo
     */
    public void showDialog(String text){
        TextArea  message = new TextArea(text, 2, 50);
        Command[] cmds    = new Command[] { new Command("Aceptar")};
        Dialog.show("Atención",  message, cmds);
    }

    /**
     * Implementación de ActionListener.
     * Tratamiento de eventos
     */
    public void actionPerformed(ActionEvent event) {
        Object source = event.getSource();

        // Si ha pulsado el botón de salir, mostramos un cuadro de
        // diálogo y salimos
        if (source == this.btnExit) {
            this.showDialog("Hasta pronto!!");
            this.midlet.destroyApp(false);
        }
    }
}

Referencias

Conclusiones

Como conclusión podríamos decir que hacian falta iniciativas como esta que hagan más atractivas las aplicaciones sin perder portabilidad ni hacer el proyecto demasiado pesado para dispositivos más antiguos…

Algunas reflexiones:

  1. Qué en el mundo no todos tienen teléfonos de última generación, pero la mayoría tienen Java preinstalado.
  2. El porcentaje de personas que tienen teléfono es muy superior al porcentaje de personas que tienen ordenador.
  3. No hace falta ser Julio Verne, para ver que todo evoluciona rápidamente y que seguramente en breve todos tendremos en nuestros bolsillos cacharros tan potentes como los ordenadores de hace unos años.

Otra cosa, recuerda que esto no es más que un tutorial, hay más puntos al respecto sobre los que profundizar.. eso sí, ahora te toca a tí pegarte con ello.

Carlos García Pérez. Creador de MobileTest, un complemento educativo para los profesores y sus alumnos.

cgpcosmad@gmail.com

1 COMENTARIO

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad