Showing posts with label MIDlet. Show all posts
Showing posts with label MIDlet. Show all posts

Thursday, November 27, 2008

BAJEMOS A ECHAR UN VISTAZO


INTERFACES DE BAJO NIVEL

Bueno, en las entregas anteriores hablamos de las interfaces de alto nivel; comentábamos que estas interfaces son de las más fáciles de implementar pues su presentación gráfica queda a cargo del dispositivo en que se ejecute la aplicación.
Esto nos permite ahorrar tiempo y esfuerzo, aunque en ocasiones será necesario tomar el control de la presentación, por ejemplo: Si lo que estamos desarrollando es un videojuego.

REGLA No. 1:
Antes de comenzar, es conveniente que establecer una regla : "Todas las pantallas que vayamos a crear usando las APIs de bajo nivel heredan de la clase Canvas".

Por esta razón, lo primero de todo es conocer a fondo esta clase y luego iremos profundizando en cada uno de los elementos que la componen.
La clase Canvas es la superclase de todas las pantallas que usan las APIs de bajo nivel, al igual que Screen lo era para las pantallas que usaban las APIs de alto nivel.

CONVIVENCIA PACIFICA:
Sin embargo, en la relación de APIs de alto y bajo nivel, no hay nada escrito, ésto es : "No existe ningún impedimento que nos permita usar en el mismo MIDlet pantallas tanto derivadas de Canvas como de Screen"

La clase Canvas permite manejar eventos de bajo nivel y dibujar cualquier cosa por pantalla. Es por ésa razón que se usa como base para la realización de juegos.

Esta clase posee un método abstracto paint() que debemos implementar de manera obligatoria (Por nuestra propia voluntad) y es la encargada de dibujar en la pantalla del dispositivo.


Veamos un ejemplo para irnos familiarizando:


BajoNivel.java


import java.io.IOException;
import javax.microedition.lcdui.*;
public class BajoNivel extends Canvas implements CommandListener {
private PBajoNivel midlet;
private Command salir;
private Image imgFondo, imgTriste;
public BajoNivel(PBajoNivel mid) {
try {
imgFondo = Image.createImage("/fondo.PNG");
imgTriste = Image.createImage("/triste.PNG");
} catch (IOException e) {
e.printStackTrace();
}
salir = new Command("Salir", Command.EXIT,1);
this.midlet = mid;
this.addCommand(salir);
this.setCommandListener(this);
}
public void paint(Graphics g) {
g.setColor(255,255,255);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0,0,0);
g.drawImage(imgFondo, 0, 0, 0);
g.drawImage(imgTriste, 40, 40, 0);
}
public void commandAction(Command c, Displayable d){
if (c == salir){
midlet.salir();
}
}
}



Esta rutina es la que nos mostrará en el dispositivo la pantalla, nótese que estamos utilizando dos imágenes fondo.PNG y triste.PNG, estos archivos los colocamos en el directorio de RES en nuestro proyecto.


Ahora veamos el código del MIDlet que lo mandará llamar.


PBajoNivel.java
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class PBajoNivel extends MIDlet {
private BajoNivel panCanvas;
private Display pantalla;
public PBajoNivel() throws Exception{
pantalla = Display.getDisplay(this);
panCanvas = new BajoNivel(this);
}
public void startApp() {
pantalla.setCurrent(panCanvas);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void salir(){
destroyApp(false);
notifyDestroyed();
}
}


Como se observa, PBajoNivel.java se limita a declarar un objeto pancanvas heredado de la clase BajoNivel.


Veamos dos ejemplos de ejecutar ésta aplicación en dos modelos distintos de cellular, a fin de que el lector pueda constatar la diferencia de despliegue entre uno y el otro.












Sunday, November 23, 2008

EL RESTO DE LAS INTERFACES

En las útimas dos entregas, hemos visto el uso de dos componentes para el uso de menús, vimos la clase LIST y CHOICEGROUP; vimos que básicamente la diferencia entre ambas es que la clase LIST no está subordinada a la clase FORM; ésto es, que no es necesario crear primero un objeto tipo FORM para luego agregar el objeto LIST.



private Display display;

private List miLista;

...

display = Display.getDisplay(this);

miLista = new List("Opciones", List.IMPLICIT);
miLista.append("Altas", null);
miLista.append("Bajas", null);
miLista.append("Consultas", null);
miLista.append("Modificaciones", null);
miLista.append("Impresion", null);
...


display.setCurrent(miLista);



Mientras que un objeto CHOICEGROUP debe estar unido a un objeto FORM.



private Display miDisplay;
private Form miForma;
private ChoiceGroup miGrupo;


...

miDisplay = Display.getDisplay(this);
miForma = new Form("MENU PRINCIPAL");


...

miGrupo = new ChoiceGroup("Opciones: ", ChoiceGroup.EXCLUSIVE);
miGrupo.append("Altas", null);
miGrupo.append("Bajas", null);
miGrupo.append("Consultas", null);
miGrupo.append("Modificaciones", null);
miGrupo.append("Impresion", null);


...

miForma.append(miGrupo);

...
display.setCurrent(miLista);




Pero además de estas clases contamos con muchas otras más como...


Class Ticker

Util para mostrar mensajes en forma de una marquesina deslizándote lado a lado de la pantalla del usuario.


Class DateField

Util para manejar fechas, ya sea para despliegue o para solicitar al usuario que proporcione una fecha en específico.



Class ImageItem

Util para trabajar con archivos de imágenes en nuestra aplicación. Ya lo veremos más adelante pero con esta herramienta podremos agregarle un atractivo visual que lo haga más amigable y agradable para el usuario.


Class TextField

Util para manejar texto; que puede ser de despliegue solamente o bien, para pedir al usuario que teclee datos. Como pueden password, números, nombres, etc.



Hay que recordar que las clases gráficas de alto nivel, tienen la facilidad de que se adaptan al tipo de despliegue con que cuenta el dispositivo en el cual estamos trabajando.

En otras palabras, nosotros llamamos las clases y creamos los objetos en nuestra aplicación, pero la presentación visual queda bajo el control del hardware.



Veamos ahora, el uso de las clases que acabamos de mencionar, en un ejemplo.


import java.io.IOException;
import java.util.Date;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.DateField;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.ImageItem;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.TextField;
import javax.microedition.lcdui.Ticker;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;



public class MIDOtros extends MIDlet implements CommandListener, ItemStateListener {
private Ticker miMarquesina;
private DateField miFecha;
private ImageItem miImagen;
private TextField miHumor;
private Image imgSerio, imgFeliz, imgTriste;
private Command Salir;
private Display miDisplay;
private Form miForma;


public MIDOtros() {
try {
imgSerio = Image.createImage("/serio.PNG");
imgFeliz = Image.createImage("/feliz.PNG");
imgTriste = Image.createImage("/triste.PNG");
} catch (IOException e) {
e.printStackTrace();
}


Date wHoy = new Date();
miDisplay = Display.getDisplay(this);
miFecha = new DateField("Dia de hoy",DateField.DATE);
miFecha.setDate(wHoy);
miHumor = new TextField("% de Animo", "50", 2, TextField.NUMERIC);
miMarquesina = new Ticker("Ejemplo de Graficos de Alto Nivel. Tutorial para el Desarrollo de aplicaciones en móviles, País México. Noviembre del 2008");
miForma = new Form("Otros Items");
Salir = new Command("Salir", Command.EXIT, 0);
miImagen = new ImageItem(null, imgSerio, 0, null);
miForma.setTicker(miMarquesina);
miForma.append(miFecha);
miForma.append(miImagen);
miForma.append(miHumor);
miForma.addCommand(Salir);
miForma.setCommandListener(this);
miForma.setItemStateListener(this);
}


protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
}


protected void pauseApp() {
}


protected void startApp() throws MIDletStateChangeException {
this.miDisplay.setCurrent(this.miForma);
}


public void commandAction(Command arg0, Displayable arg1) {
if (arg0 == Salir){
try {
destroyApp(false);
} catch (MIDletStateChangeException e) {
e.printStackTrace();
}
notifyDestroyed();
}
}


public void itemStateChanged(Item arg0) {
if (arg0 == miHumor){
int wValor = Integer.parseInt(miHumor.getString());
if (wValor <> 70) {
miImagen.setImage(imgFeliz);
} else {
miImagen.setImage(imgSerio);
}
}
}
}
}




Como se observa, en esta aplicación manejamos archivos de imagen :


imgSerio = Image.createImage("/serio.PNG");
imgFeliz = Image.createImage("/feliz.PNG");
imgTriste = Image.createImage("/triste.PNG");




Que son archivos tipo PNG, este tipo nos permite manejar imágenes con una buena y razonable resolución y almacenarlos en poco espacio.
Bien, una vez compilado nuestro código; podemos ejecutarlo y verlo en acción.

Friday, November 7, 2008

INTERFAZ DE USUARIO

Interfaces Gráficas de Usuario de Alto Nivel



En esta entrega hablaremos de la interface gráfica de alto nivel, esta interfaz usa componentes tales como botones, cajas de texto, formularios, etc. Estos elementos son implementados por cada dispositivo y la finalidad de usar las APIs de alto nivel es su portabilidad. Al usar estos elementos, perdemos el control del aspecto de nuestra aplicación ya que la estética de estos componentes depende exclusivamente del dispositivo donde se ejecute. En cambio, usando estas APIs de alto nivel ganaremos un alto grado de portabilidad de la misma aplicación entre distintos dispositivos. Fundamentalmente, se usan estas APIs cuando queremos construir aplicaciones de negocios.

Wednesday, November 5, 2008

CREACION Y ADMINISTRACION DE PROYECTOS


PONIENDO A TRABAJAR EL WIRELESS TOOLKIT



Todo proyecto comienza con un paso, y éste sería darle un click al ícono del Wireless Toolkit que se mira en la imagen.


Cuando se crea un proyecto, el Wireless Toolkit se encarga de crear un árbol de directorios en los que podremos almacenar nuestro código, los recursos que necesitemos en la aplicación y los archivos de instalación, entre otros.



Ya sea con la opción File-> New Project, o con el icono de New Project que aparece en pantalla; se puede crear un proyecto.







Para la creación del nuevo proyecto, deberemos proporcionar dos cosas:

  1. Nombre del Proyecto

  2. Nombre de la clase MIDlet

Por ejemplo, podemos dar como nombre del proyecto: Mi Primera Aplicación para J2ME, y como nombre de la clase MIDlet: MiPrimerMidlet.java y presionemos el botón Create Project.

Para ser nuestra primera práctica y antes de que entremos de lleno a conocer los perfiles (MIDP) y las configuraciones (CLDC), seleccionemos la siguiente opción que se muestra en la pantalla y presionemos después el botón OK.

Como mencionaba anteriormente, al momento de seleccionar un nuevo proyecto, el Wireless Toolkit crea una estructura de directorios en los que almacenaremos todo lo necesario para desarrollar la aplicación.


Y en ésta imagen lo podemos apreciar, Wireless Toolkit ha creado para nuesta aplicación la estructura de directorios en D:\Documents and Settings\wz2qch\j2mewtk\2.5.2\apps\Mi Primera Aplicacion para J2ME.

Mencionemos los distintos subdirectorios que nos ha creado:

bin .- En este directorio tendremos los archivos de instalación de la aplicación; que serían un archivo *.jar, otro *.jad y uno llamado MANIFEST.MF
lib .- Si además de las class y librerías que nos proporciona J2ME, utilizamos alguna otra; es en este lugar donde podemos almacenarlas para ser llamadas por nuestra aplicación.

res .- Es el lugar en donde podemos almacernar nuestros recursos; que pueden archivos de imágenes, documentos, etc; necesarios para nuestra aplicación.
src .- Y por último pero no por eso menos importante, es este directorio en donde almacenaremos nuestro código fuente, nuestros archivos *.java que darán funcionalidad a lo que desarrollemos.

Cuando yá se empieza a trabajar y se compilan los proyectos; se crean otros directorios adicionales como el classes, el tmpclasses y el tmplib.

Pongamos en el directorio src el código que creamos anteriormente y que llamamos MiPrimerMidlet.java.

Para compilarlo, bastará con presionar el botón BUILD en el menú principal de Wireless Toolkit y si no hay errores de compilación, podremos ejecutarlo en el emulador presionando el botón RUN.
Como se observa en la imagen, se desplegará nuestra aplicación gracias al emulador por default. Es posible cambiar este emulador por otro, para tener una representación mas fidedigna de cómo se vería en un modelo distinto de móvil.
Esto se hace seleccionando el emulador que deseemos, en la caja de combo DEVICE, y podemos seleccionar entre:
  1. DefaultPhoneColor
  2. DefaultGrayPhone
  3. MediaControlSkin
  4. QwertyDevice

Tuesday, November 4, 2008

LA CLASE MIDlet: LA MADRE DE TODOS

Todo desarrollo en J2ME tiene una base, esta base es la clase MIDlet.



Echemosle un vistazo a la documentación de SUN MicroSystems...



"javax.microedition.midlet Class MIDlet
java.lang.Object ---------> javax.microedition.midlet.MIDlet


public abstract class MIDlet extends Object


A MIDlet is a MID Profile application. The application must extend this class to allow the application management software to control the MIDlet and to be able to retrieve properties from the application descriptor and notify and request state changes. The methods of this class allow the application management software to create, start, pause, and destroy a MIDlet. A MIDlet is a set of classes designed to be run and controlled by the application management software via this interface. The states allow the application management software to manage the activities of multiple MIDlets within a runtime environment. It can select which MIDlets are active at a given time by starting and pausing them individually. The application management software maintains the state of the MIDlet and invokes methods on the MIDlet to notify the MIDlet of change states. The MIDlet implements these methods to update its internal activities and resource usage as directed by the application management software. The MIDlet can initiate some state changes itself and notifies the application management software of those state changes by invoking the appropriate methods.
Note: The methods on this interface signal state changes. The state change is not considered complete until the state change method has returned. It is intended that these methods return quickly."



Para todos aquellos que no mastican muy bien el inglés, no se preocupen; lo más importante lo veremos por medio de ejemplos.



La clase MIDlet cuenta con tres métodos protegidos, ésto significa, no pueden faltar, y son los siguientes:

  1. startApp()

  2. pauseApp()

  3. destroyApp(boolean unconditional)
El método startApp() es el dá inicio a todo, es como el public avoid main que veíamos en los códigos de J2SE. el pauseApp() en el caso de tener que interrumpir la ejecución de la aplicación, por ejemplo: Si recibimos una llamada o entra un mensaje a nuestro dispositivo móvil.


El método destroyApp() sería el encargado de dar por terminada la aplicación, desactivándolo y procediendo a su destrucción como proceso activo en memoria.

Para que lo podamos entender mejor, vamos a ver un ejemplo:


MiPrimerMidlet.java

import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.StringItem;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class MiPrimerMidlet extends MIDlet {
Display Despliegue;
Form Pantalla;
StringItem txtBox;

public MiPrimerMidlet() {
Despliegue = Display.getDisplay(this);
Pantalla = new Form("Primer Midlet");
StringItem txtBox = new StringItem("MI PRIMER MIDLET !!!", null);
Pantalla.append(txtBox);
}

protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
}

protected void pauseApp() {
}

protected void startApp() throws MIDletStateChangeException {
Despliegue.setCurrent(Pantalla);
}
}

Analicemos éste código, notemos primero que nada que entre las librerías que estamos importando, hay dos que hacen referencia directa a la clase MIDlet


import javax.microedition.midlet.MIDlet;

import javax.microedition.midlet.MIDletStateChangeException;

La primera línea nos permite heredar la clase MIDlet, la segunda nos permite manejar los cambios de estado, esto es: el startApp, pauseApp y el destroyApp que hemos estado mencionando.


Siguiendo con el análisis vemos como nuestra aplicación hereda a la clase MIDlet

public class MiPrimerMidlet extends MIDlet {


Y adicional a ésto manejos tres elementos más: Un Display, una Form y un StringItem.



La clase Display nos dá el poder de controlar la pantalla del dispositivo, la Form nos permite desplegar algo en la pantalla y agregar allí nuestros controles, en este caso: Un letrero que diga MI PRIMER MIDLET !!!



La clase Display toma control de la pantalla del dispositivo con el método getDisplay en la línea

Despliegue = Display.getDisplay(this);

Además de éste método, tiene otros igual de útiles como :

  1. 1.- getBestImageHeight(int imageType)
  2. 2.- getBestImageWidth(int imageType)
  3. 3.- setCurrent(Alert alert, Displayable nextDisplayable)
  4. 4.- setCurrent(Displayable nextDisplayable)

La clase Form nos permite desplegar algo en la pantalla y agregar allí los componentes que deseamos.

Como se puede observar en el ejemplo, declaramos un objeto StringItem (txtBox), le asignamos un letrero que dice MI PRIMER MIDLET !!! y a continuación lo agregamos al objeto Form (Pantalla).

Despliegue = Display.getDisplay(this);

Pantalla = new Form("Primer Midlet");

StringItem txtBox = new StringItem("MI PRIMER MIDLET !!!", null);

Pantalla.append(txtBox);

Y finalmente, asignamos este objeto Form (txtBox) con todo y componente al objeto Despliegue para poder visualizarlo.

Despliegue.setCurrent(Pantalla);

En la siguiente entrega, veremos cómo se compila, cómo se ejecuta y cómo se crean los archivos instalables de J2ME, hoy por hoy hemos terminado.