Gauge, Item y Form

(Imagen: Edgar Degas - El ajenjo)

Seguimos con la descendencia de Screen, y ahora nos toca explorar a Form y todo lo que podemos poner en él. Un Form es un subtipo de Screen que puede albergar una colección de controles de interfaz de usuario, a los que llamaremos items, y que son instancias de la clase Item.

En este post exploraremos el funcinamiento de dos subtipos de Item: Gauge y StringItem; y para esto utilizaremos un MIDlet de ejemplo tomado -como es usual- del libro de Knudsen. Este MIDlet nos mostrará un Gauge -un indicador- y un texto que nos mostrará el valor que almacena este Gauge. El código fuente es el siguiente:

package test;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Gauge;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.StringItem;
import javax.microedition.midlet.*;

/**
* @author cgavidia
*/
public class GaugeTracker extends MIDlet implements ItemStateListener, CommandListener {

private Gauge mGauge;
private StringItem mStringItem;

public GaugeTracker() {
int initialValue=3;
this.mGauge = new Gauge("Gauge Title", true, 5, initialValue);
this.mStringItem = new StringItem(null, "[value]");
this.itemStateChanged(mGauge);
}


public void startApp() {
Form form = new Form("Gauge Tracker");
form.addCommand(new Command("Exit", Command.EXIT,0));
form.setCommandListener(this);
form.append(this.mGauge);
form.append(this.mStringItem);
form.setItemStateListener(this);

Display.getDisplay(this).setCurrent(form);
}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}

public void itemStateChanged(Item item) {
if (item == this.mGauge){
this.mStringItem.setText("Value = " + this.mGauge.getValue());
}
}

public void commandAction(Command c, Displayable d) {
if (c.getCommandType() == Command.EXIT){
this.notifyDestroyed();
}
}
}



Primero definimos como atributos el Gauge y el StringItem que vamos a mostrar. Gauge es un selector que almacena un valor entero, y StringItem es una etiqueta de texto común y corriente. El constructor de Gauge que hemos usado recibe 4 parámetros: el primero es su etiqueta, el segundo un boolean que nos indica si es interactivo o no, y los dos últimos son el valor máximo y el valor inicial. Nuestro Gauge es interactivo debido a que el usuario va a poder cambiar su valor; pero existe la posibilidad de usar Gauge no-interactivos, que se utilizan para cosas como barras de progreso. Pero este no es el caso.

El constructor de StringItem recibe dos parámetros: una etiqueta y un valor. A la etiqueta le asignamos null para que no sea visible y como valor ponemos una cadena arbitraria. Y después, invocamos al método itemStateChanged, que agregamos debido a la implementación de la interfaz ItemStateListener. Los items en un form disparan eventos cuando el usuario interactúa con ellos. Para que nuestra aplicación responda a estos eventos es necesario registrar un objeto ItemStateListener (como nuestro MIDlet) dentro de un form. Esto ya lo haremos más adelante.

Terminada la ejecución del constructor y obtenida la instancia, comienza la ejecución de startApp. Lo primero a hacer es obtener un Form, y lo hacemos mediante su constructor que sólo recibe como parámetro el título. A este form le agregamos un Command para terminar la aplicación, y le asignamos como CommandListener a nuestro MIDlet. Luego, asignamos nuestros dos items - mGauge y mStringItem - al Form que acabamos de crear mediante el método append. También es necesario asignarle al Form un ItemStateListener, para manejar la lógica producto de la interacción con el usuario: esto lo hacemos mediante setItemStateListener (recordar que el MIDlet implementa ItemStateListener). Terminamos la lógica de startApp mostrando al usuario el Form recién configurado mediante setCurrent.

El usuario puede cambiar los valores del Gauge, y nosotros requerimos que cuando pase esto se actualice el texto mostrado por mStringItem. Este proceso lo realizamos en el método itemStateChanged: con setText cambiamos el valor del StringItem y con getValue obtenemos el valor del Gauge. Para finalizar, implementamos la lógica para salir de la aplicación en commandAction, de la misma manera que venimos haciéndolo hace un par de posts. Al ejecutar la aplicación, verían algo así:



Ese sería el final del post. Hasta otra..!!

Basado en Wireless Java Developing with J2ME de Jonathan Knudsen.

List y MIDlets

(Imagen: Edgar Degas - The New Orleans Cotton Exchange)

En el post pasado nos encargamos de TextBox, un componente gráfico que hereda de Screen, que a su vez hereda de Displayable. Ahora, nos toca revisar a su "hermano": List, que también es del tipo Screen.

Los componentes List nos permiten seleccionar items de un grupo de alternativas posibles. Para representar a cada elemento, utilizamos una cadena de texto y/o una imagen. Es posible seleccionar uno o más elementos del List según el tipo de List que utilicemos... pero mejor esto hay que verlo con un ejemplo (tomado, una vez más, del libro de Knudsen). Construiremos un MIDlet que nos permita seleccionar entre tres opciones posibles: Airplane, Car y Hotel. Al seleccionar algún elemento se nos mostrará un alert con la selección realizada, y habilitaremos también un botón para terminar la aplicación. Entonces, he aquí el código fuente:

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package test;

import java.io.IOException;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.List;
import javax.microedition.midlet.*;

/**
* @author cgavidia
*/
public class TravelList extends MIDlet implements CommandListener {
private List mList;
private Command mExitCommand, mNextCommand;

public TravelList() {
String[] stringElements = {"Airplane", "Car", "Hotel"};
Image[] imageElements = {this.loadImage("/airplane.png"), this.loadImage("/car.png"), this.loadImage("/hotel.png")};
this.mList = new List("Reservation Type", List.IMPLICIT, stringElements, imageElements);
this.mNextCommand = new Command("Next", Command.SCREEN, 0);
this.mExitCommand = new Command("Exit", Command.EXIT, 0);
mList.addCommand(mExitCommand);
mList.addCommand(mNextCommand);
mList.setCommandListener(this);
}


public void startApp() {
Display.getDisplay(this).setCurrent(this.mList);
}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}

public void commandAction(Command c, Displayable d) {
if (c == this.mNextCommand || c== List.SELECT_COMMAND){
int index = this.mList.getSelectedIndex();
Alert alert = new Alert("Your Selection", "You chose " + this.mList.getString(index), null, AlertType.INFO);
Display.getDisplay(this).setCurrent(alert, this.mList);
}else if (c == this.mExitCommand){
this.notifyDestroyed();
}
}

private Image loadImage(String string) {
Image image = null;
try {
image = Image.createImage(string);
} catch (IOException ex) {
ex.printStackTrace();
}
return image;
}
}


Al tratarse de un MIDlet extendemos de MIDlet (redundante, lo sé), e implementamos CommandListener para que nuestra misma clase responda a los eventos de los Commands (mediante el método commandAction, pero esto ya lo sabían). Definimos como atributo un List (mList) y dos Commands, uno para seleccionar elementos y otro para salir.

Recordando el ciclo de vida de un MIDlet, lo primero a ejecutarse es el constructor. Como les mencionaba, cada elemento del List está representado visualmente por una cadena de texto y una imagen, y el constructor nos permite pasarle como parámetros un array con todas las cadenas de texto y otro con todas las imágenes: para esto usamos a stringElements y a imageElements. Antes de olvidarlo, es necesario que agreguen las imágenes a su proyecto de aplicación móvil. Si están usando Java Platform Micro Edition SDK 3.0, es necesario importar la carpeta con las imágenes en "Resources".

Pero volvamos al constructor de List: el primer parámetro es el título y el segundo es el tipo de List. Al asiganarle List.IMPLICIT como tipo nos aseguramos que el usuario sólamente pueda realizar una selección al List e inmediatamente realizar una acción de la aplicación (sin necesidad de confirmación). También inicializamos los Commands mNextCommand y mExitCommand, y se los asignamos al List que acabamos de crear. Para finalizar, le asignamos también como Listener al List a nuestro propio MIDlet.

En startUp simplemente mostramos el List que ya hemos configurado adecuadamente en el constructor. Deberían poder ver algo así:



El usuario tiene la posibilidad de seleccionar una opción del List o terminar la aplicación, y todo esto es manejado en el método commandAction. Al tratarse de un List IMPLICIT, al método commandAction va a llegar un valor especial como parámetro Command: List.SELECT_COMMAND. En caso sea esta la acción realizada por el usuario, se mostrará un Alert que indicará la opción escogida, mediante el método getString de mList. Hemos usado el método setCurrent de dos parámetros para que después de mostrado el alert se muestre nuevamente la lista (el segundo parámetro) al usuario.

Y dejamos al método loadImage para el final. Este método nos permite obtener referencias Image que representen las imágenes que queremos mostrar. Image no tiene constructores, pero en cambio nos ofrece el metodo createImage que, en este caso, en base a una cadena que coincide con la ruta nos devuelve el objeto Image que necesitamos.

Con esto finalizaríamos el post. ¡Hasta otra!

Basado en Wireless Java Developing with J2ME de Jonathan Knudsen.

Un MIDlet

(Imagen: Edgar Degas - La clase de danza)

Hola, queridos lectores. Primero, es necesario disculpar la ausencia de post de los últimos meses, sólamente explicable por el hecho de que no he estado estudiando nada (aunque les dije que me iba tomar un descanso); y segundo, que ya tengo en mente la siguiente certificación que pienso agregar a mi palmarés: Sun Certified Mobile Application Developer (SCMAD).

Pienso tomarmelo con calma, dado que aún no he adquirido el voucher, así que los posts serán menos frecuentes (pero espero que más sustanciosos). Para esta tarea, me he planteado leer Wireless Java Developing with J2ME de Jonathan Knudsen y una vez asimilado todo probar mis destrezas con los simuladores de uCertify para SCMAD. Al menos, ese es el plan.

Entonces,ya basta de palabrería y vayamos a lo nuestro. Un MIDLet es una aplicación MIDP, y MIDP (Mobile Information Device Profile) es una especificación para el uso de Java en dispositivos móviles, como celulares y PDA. Esto implica que desarrollamos en nuestro lenguaje favorito (ya saben la respuesta) y podemos hacer uso de API's que ya conocemos como java.lang y java.io; aunque con algunas diferencias que ya veremos luego.

Ahora, el proceso de desarrollo de MIDLets es un poquito más complicado que el de una aplicación J2SE, e incluye pasos de preverificación y empaquetamiento antes de poder ejecutar la aplicación. Para evitarnos estas molestias, es mejor utilizar un IDE que nos simplifique la vida. Yo estoy utilizando el Java Platform Micro Edition SDK 3.0 , si tienen otra IDE favorita, siéntanse libres de usarla. Entonces, sin más preámbulos, les presento a un MIDlet tomado del libro de Knudsen:

package test;

import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.*;

/**
* @author cgavidia
*/
public class TwoAlerts extends MIDlet implements CommandListener {

private Display mDisplay;
private TextBox mTextBox;
private Alert mTimedAlert;
private Alert mModalAlert;
private Command mAboutCommand, mGoCommand, mExitCommand;

public TwoAlerts() {
mAboutCommand = new Command("About", Command.SCREEN, 1);
mGoCommand = new Command ("Go", Command.SCREEN, 1);
mExitCommand = new Command("Exit", Command.EXIT, 2);
mTextBox = new TextBox ("TwoAlerts", "", 32, TextField.ANY);
mTextBox.addCommand(mAboutCommand);
mTextBox.addCommand(mGoCommand);
mTextBox.addCommand(mExitCommand);
mTextBox.setCommandListener(this);

mTimedAlert = new Alert("Network Error", "A network error ocurred. Please try again.", null, AlertType.INFO);
mModalAlert = new Alert("About TwoAlerts", "TwoAlerts is a simple MIDlet that demostrates the use of alerts.",null, AlertType.INFO );
mModalAlert.setTimeout(Alert.FOREVER);

}


public void startApp() {
mDisplay = Display.getDisplay(this);
mDisplay.setCurrent(mTextBox);
}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}

public void commandAction(Command c, Displayable d) {
if (c == this.mAboutCommand){
mDisplay.setCurrent(mModalAlert);
}else if (c == this.mGoCommand){
mDisplay.setCurrent(mTimedAlert, mTextBox);
}else if (c == this.mExitCommand){
this.notifyDestroyed();
}
}
}



Las aplicaciones MIDP están representadas por instancias de la clase javax.microedition. midlet.MIDlet, y es por esto que nuestra clase la extiende. Antes de ejecutar la aplicación, es necesario crear la instancia y por ende el constructor es invocado. En nuestro constructor, inicializamos todos los atributos de nuestro MIDlet, pero mejor veamos a cada uno de ellos con paciencia:

  • Asignamos valores a los tres atributos Command que tenemos. Un command, es algo con lo que el usuario puede interactuar: es algo así como un botón. El constructor de Command que usamos nos solicita un nombre, un tipo y una prioridad. Los dos primeros son de tipo SCREEN (tipo Genérico) y el último es del tipo EXIT (para finalizar la aplicación).
  • Nuestro MIDlet también tiene un atributo TextBox, que le permite al usuario ingresar una cadena de texto. Para poder crear el TextBox, hemos necesitado especificar un título, el texto inicial , la cantidad máxima de caracteres y sus restricciones. Como hemos utilizado TextField.ANY como restricción, el usuario es libre de ingresar cualquier texto.
  • Toda instancia de Displayable está asociada a los Commands con los que interactúa. La clase TextBox hereda de Displayable, por lo que vamos a asociar los Commands creados con el TextBox mTextBox haciendo uso de su método addCommand.
  • También es necesario saber que hacer cuando un usuario interactúa con un Command. Para esto se define un objeto listener, que es notificado cuando el usuario invoca a cualquier Command de nuestro Displayable (en nuestro caso, nuestra TextBox). Se requiere que el listener implemente la interfaz CommandListener, y eso es lo que está haciendo nuestra clase. Para registrar el listener mTextBox, invocamos a su método setListener.
  • Después es necesario asiganarle valores a los dos atributos Alert del MIDlet. Un Alert es un mensaje informativo para el usuario, y MIDP nos permite utilizar dos tipos de Alert's: los que se muestran en pantalla por un período de tiempo para después desaparecer y los que son mostrados hasta que el usuario realice alguna acción (por ejemplo, seleccionar OK). El atributo mTimedAlert es del primer tipo y mModalAlert es del segundo (mediante la sentencia mModalAlert.setTimeout(Alert.FOREVER) le indicamos que se muestre por un tiempo indeterminado.

Después de ejecutado el constructor, el ciclo de vida del MIDlet nos indica que el método startApp es ejecutado. Lo primero que hacemos es obtener una instancia de Display mediante getDisplay. La clase Display es la que nos va a permitir administrar la pantalla del disposivo. Nota importante: El método getDisplay no puede ser invocado en el constructor, y tiene que invocarse al inicio del método startAp.

Una vez que tenemos una referencia a Display, le indicamos que elementos mostrar mediante el método setCurrent, que recibe como parámetros instancias de Displayable. Entonces, hacemos que se muestre en pantalla el TextBox que hemos inicializado, ya que TextBox es una clase que hereda de Displayable.

Hemos implementado el método commandAction debido a nuestra interfaz CommandListener. El método es bastante sencillo, y nos muestra los alerts que hemos creado en función al Command seleccionado mediante el método setCurrent, que ya explicamos. Si es que el usuario selecciona el botón EXIT se invoca a notifyDestroyed, con lo que nuestro MIDlet comete harakiri y es destruido.

Ahora ya tenemos todo listo para ejecutar el MIDlet,lo compilamos, ejecutamos y si están usando el IDE que les recomendé, nuestra aplicación se ejecutaría en el emulador y verían algo como esto:



Y una vez más, esto ya se hizo demasiado largo. Nos vemos la próxima!

Basado en Wireless Java Developing with J2ME de Jonathan Knudsen.