Como continuación del ejemplo #21, ahora se verá en este ejemplo como enviar datos desde la interfaz de alto nivel a la interfaz de bajo nivel, este es una forma para poder capturar datos del usuario y usarlos en la clase GameCanvas, recuerde que en esta clase no existe forma alguna para que el usuario introduzca los datos.
El ejemplo de hoy va a hacer uso del código Java del ejemplo #19, el cuál puedes ver dando clic aqui, el ejemplo, como se recordará muestra la animación de una pelotita que está rebotando por toda la pantalla, una y otra vez, pero lo hace a una velocidad constante siempre, hoy se mostrará cómo se puede elegir desde la interfaz de alto nivel, la velocidad de la pelotita la cual se enviará a la interfaz de bajo nivel para que la pelotita responda a esta velocidad.
Interfaz de alto nivel
La imagen siguiente muestra la interfaz de alto nivel para este ejemplo:
Si has seguido el blog desde los artículos iníciales, sabrás fácilmente realizar la interfaz de usuario mostrada en la figura anterior, lleva dos TextField y un okCommand.
Por otro lado, en el ejemplo #19 se hace uso de la clase llamada “Animacion” también vista ya en varios ejemplos del blog, el nombre de la clase es importante para poder mandarla llamar desde la interfaz de alto nivel
Vea el código siguiente:
int velx = Integer.parseInt(textField.getString());
int vely = Integer.parseInt(textField1.getString());
Con ese par de instrucciones se obtiene el valor que el usuario ingreso en los TextField, en las variables de tipo entero llamadas “velx” y “vely”, estas variables se envían como parámetros a la interaz de bajo nivel, tal y como se observa en la siguiente instrucción:
Animacion canvas = new Animacion(this, velx, vely);
Recuerde con esa instrucción se crea un objeto llamado “canvas” de la clase “Animación, vea las variables “velx”, y “velY” son enviadas a la clase “Animacion” como parámetros. Así de fácil se envían los datos de la interfaz de alto nivel a la clase que deriva de GameCanvas.
El código completo, cuando se presiona el comando que nos envía a la interfaz de bajo nivel entonces queda así:
int velx = Integer.parseInt(textField.getString());
int vely = Integer.parseInt(textField1.getString());
Animacion gameCanvas = new Animacion(this, velx, vely);
Display.getDisplay(this).setCurrent(gameCanvas);
Si no tienes idea de donde se ubica este código al final del post viene el video tutorial para que no quede duda alguna.
Cambios a la clase "Animacion"
Este es el código final del ejemplo #19 que hacia rebotar la pelotita por toda la pantalla:
import javax.microedition.lcdui.game.*;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
public class Animacion extends GameCanvas implements Runnable {
Graphics g;
Thread subproceso;
Image fondo, pelota;
public Animacion() {
super(true);
g = getGraphics();
try {
fondo = Image.createImage("/fondo.jpg");
pelota = Image.createImage("/pelotita.gif");
} catch (Exception e) { }
subproceso = new Thread(this);
subproceso.start();
}
Vea las variables "velX" y "velY", se declaran en el método run() y ahí son inicializadas con un valor fijo de 5 y 3 respectivamente, bueno pues en primer lugar hay que quitarlas de ahí, porque ahora los valores para estas variables vienen de la interfaz de alto nivel, se declaran a continuación de la definición de la clase, con eso basta para poder las usar en todo lo largo del programa.
Otro cambio es el constructor que ahora recibe tres parámetros, el primero es el MIDlet y los otros dos son las variables de la velocidad que se enviaron desde la interfaz de alto nivel, enseguida se muestra parte del código para el constructor:
// Declaración de las variables (después de la clase)
int velX;
int velY;
public Animacion(HelloMIDlet mid, int vx, int vy) {
// Aquí va el código para el constructor
VelX = vx;
VelY = vy;
}
Justo aquí se asignan los valores que vienen de la interfaz de alto nivel a las variables de la clase, con esto basta para poder comunicarnos, para poder enviar datos desde la interfaz de alto nivel, al hacer lo anterior la velocidad de la pelotita va respondiendo al valor que se ingreso en la interfaz.
Básicamente eso son los cambios, más significativos, lo que sigue es repetir lo que se hizo en la entrada anterior (ejemplo #21), que es lo de agregar los comandos para cambiarse de una interfaz a otra, esto ya se explico con detalle, en ese ejercicio, así que no tiene caso volverlo repetir.
Fiel a mi costumbre y para evitar malos entendidos, y para eliminar las dudas que pudieran surgir de lo visto arriba, a continuación se muestra el video tutorial para este ejemplo.
Aún así, por si hubiera dudas del video puesto que hubo una parte de copiar y pegar, voy a colocar en este enlace, un archivo comprimido que incluye toda la carpeta que genera NetBeans para este ejemplo, la versión que se uso fue la 6.8, ahí está el código fuente completo, incluso en la carpeta “dist” se encuentra el archivo JAR para enviarlo directo al celular y probar este ejemplo en el teléfono.
En modo gráfico (interfaces de bajo nivel), no existe forma alguna para poder capturar valores tal y como se hace con las interfaces de alto nivel, ahí simplemente se coloca un TextField y se capturan valores como ya se ha visto en varios ejemplos en este blog, en la clase GameCanvas no existe esa posibilidad hay que usar otros medios y uno de ellos es mezclando las interfaces de bajo nivel con las de alto nivel.
Por ejemplo, pensando en el único ejemplo de animación que hemos visto, el de la pelotita que rebota por toda la pantalla, sería interesante poder elegir la velocidad a la que rebota la pelotita, sería interesante que el usuario escribierá que velocidad desea y que la animación respondiera a ello, bueno pues este ejemplo es el primer paso para llegar ahí a la lectura de datos en modo gráfico, así que iniciemos.
Hola Mundo con interfaces de alto nivel
Existe una entrada del blog, de hecho es casi de las iniciales que muestra cómo crear el clásico ejemplo “hola mundo” con interfaces de alto nivel, lo puedes consultar aquí para que lo recuerdes:
Basándonos en ese ejemplo fácilmente se puede crear esta pantalla
Veamos ahora el "hola mundo" en modo gráfico.
“Hola Mundo” con interfaces de bajo nivel
Por otro lado el blog tiene un articulo llamado “Ejemplo #17 Hola Mundo usando GameCanvas” el cuál puedes ver dando clic aqui, el resultado del código se puede ver en la siguiente pantalla
La idea es agregar un botón o comando a cada una de las interfaces, que me permita cambiarme de una interfaz a otro, por lo pronto, este ejemplo solo mostrará los mensajes que se muestran en las imágenes de arriba. Vamos a iniciar agregando el botón en la interfaz de alto nivel porque es más fácil.
Agregando el Command a la interfaz de alto nivel
La idea recuerde es agregar un botón o comando para cambiarme a la interfaz de bajo nivel, existe otra entrada del blog, llamada Ejemplo #6 como usar objetos de tipo Command, puedes consultarlo dando clic aquí, ahí se observa con detalle cómo se puede agregar un comando, como el de la figura siguiente:
El comando se llama “Modo Gráfico” y me permitirá cambiarme de interfaz, es muy fácil crear un comando usando interfaces de alto nivel, siguiendo las instrucciones del ejemplo #6, básicamente solo es de arrastrar y soltar el comando.
Cuando se presione el comando se debe crear el objeto de la clase GameCanvas, para que aparezca en la pantalla, afortunadamente existe otro artículo en el blog, bueno, hay varios que muestran como agregar código cuando se presiona el botón, el artículo se llama Ejemplo #7 “programa que calcula el área de un rectángulo”, en la parte final viene como agregar el código cuando se presione el comando, lo puedes consultar dando clic aquí.
Justo donde se indica en el ejemplo #7 se debe agregar el código (si no deseas ver el ejemplo, no te preocupes, al final viene el video-tutorial). El primer paso es crear una instancia de la clase que deriva de GameCanvas, para ello se debe conocer el nombre de la clase, la clase definida en el Ejemplo #17 se llama EjemploGameCanvas, para mostrar en pantalla lo que está en la clase GameCanvas se agrega el siguiente código:
EjemploGameCanvas gCanvas = new EjemploGameCanvas();
Display.getDisplay(this).setCurrent(gCanvas);
Primero se crea el objeto de la clase EjemploGameCanvas y posteriomente se muestra en pantalla este objeto, logrando que se ve el mensaje de “Hola mundo…”.
Por otro lado, si se desea interactuar en los dos modos de pantalla, se debe enviar una referencia del modo de texto al modo grafico, para poder trabajar en los dos lados, si no lo hago así no podré regresar del modo gráfico al modo de texto, basta pues agregar como parámetro la palabra “this”, que en este caso “this” hace referencia al MIDlet principal, entonces el código final queda así:
EjemploGameCanvas gCanvas = new EjemploGameCanvas(this);
Display.getDisplay(this).setCurrent(gCanvas);
Más adelante se verá el uso que se le dará a ese parámetro que fue enviado al Canvas.
Como lo mencionaba, si se tienen dudas de donde ubicar el código, al final de este post, como siempre, el video tutorial dará todas las respuestas. Pasemos entonces a la interfaz de bajo nivel que es algo más complicado que lo visto ahora.
Agregando el Command a la interfaz de bajo nivel
La idea recuerde, es agregar a la clase GameCanvas también, un botón o comando para que al presionarlo pueda cerrar está pantalla en modo gráfico y abrir la pantalla mostrando la interfaz de alto nivel.
Desgraciadamente en el modo gráfico, tengo que hacerlo todo manualmente, no es como en las interfaces de alto nivel, como se vio arriba, donde solo se arrastran y sueltan los botones en el área de trabajo y NetBeans genera todo el código, no aquí no es así, hay que teclearlo todo, eso es bueno porque así se aprende nuevo código nuevas funciones que no se aprendieron con las interfaces de alto nivel y que NetBeans genero automáticamente.
Vemos primeramente el código final del ejemplo #17, el código Java que me permite mostrar el “hola mundo…” en bajo nivel, ya se analizó a detalle y quedo así:
public class EjemploGameCanvas extends GameCanvas implements Runnable {
Graphics g;
public EjemploGameCanvas () {
super(true); // código del constructor
g = getGraphics();
Thread subproceso = new Thread(this);
subproceso.start();
}
public void run() {
// pantalla en negro
g.setColor(0x000000);
g.fillRect(0, 0, getWidth(), getHeight());
// dibujo de las letras “hola mundo…
g.setColor(0xff00FF);
g.drawString("Hola mundo, con GameCanvas", 0, 60, Graphics.LEFT || Graphics.TOP);
flushGraphics();
}
}
Agregando el parámetro al constructor
Vea el constructor, obviamente no tiene parámetros, nosotros desde la interfaz de alto nivel le enviamos uno, que era, dicho sea de paso el MIDlet (por medio de la palabra “this”), hay que recibir el parámetro con una variable para que haya una correspondencia, recuerde el post de los métodos con parámetros.
El MIDlet, fue creado automáticamente por Netbeans, viendo el código se observa que el MIDlet se llama HelloMidlet entonces el parámetro se tiene que recibir como una variable o más bien dicho como una instancia de tipo HelloMidlet así:
public EjemploGameCanvas ( HelloMIDlet hm) {
// código del constructor
}
Se recibe como parámetro la instancia o el objeto de la clase HelloMIDlet, es llamada "hm", debe haber una variable declarada después de la clase, de ese mismo tipo para poder almacenar el párametro que llega desde el MIDlet y también para posteriormente usarla a lo largo de toda la clase que deriva de GameCanvas, el código es así:
HelloMIDlet hellomidlet;
Esta variable se inicializa dentro del constructor con el parámetro que llego de la interfaz de alto nivel, así:
hellomidlet = hm;
Con esto, por decirlo así se tiene el MIDlet dentro de GameCanvas y se puede usar en cualquier lado de la clase, por medio del objeto llamado “hellomidlet” el código completo de la clase va quedando así:
public class EjemploGameCanvas extends GameCanvas implements Runnable {
Graphics g;
HelloMidlet hellomidlet;
public EjemploGameCanvas (HelloMIDlet hm) {
super(true); // código del constructor
hellomidlet = hm;
g = getGraphics();
Thread subproceso = new Thread(this);
subproceso.start();
}
public void run() {
// pantalla en negro
g.setColor(0x000000);
g.fillRect(0, 0, getWidth(), getHeight());
// dibujo de las letras “hola mundo…
g.setColor(0xff00FF);
g.drawString("Hola mundo, con GameCanvas", 0, 60, Graphics.LEFT || Graphics.TOP);
flushGraphics();
}
}
Como agregar el Command al GameCanvas
Aún no se ha agregado ningún botón o comando, veamos que se necesita para agregar los botones con código
Agregar la interfaz CommandListener
Para agregar un botón o comando, primeramente se tiene que agregar la interfaz CommandListener, al igual que la interfaz Runnable, se agrega a la definición de la clase así:
public class EjemploGameCanvas extends GameCanvas implements Runnable, CommandListener {
Esta interfaz me permite “escuchar” los eventos generados por los comandos o botones que se agreguen.
Se debe agregar la siguiente instrucción, arriba, en la sección de los "imports":
import javax.microedition.lcdui.*;
Necesaria para poder usar el CommandListener
Por otro lado, no basta con agregar la interfaz CommandListener para “escuchar” los comandos, debemos indicar, que los comandos se van a “escuchar” en el GameCanvas, esto se logra con la siguiente instrucción, es como un enlace entre el CommandListener y el GameCanvas actual
setCommandListener(this);
Recuerde agregar el “this”, palabra reservada de java que habla del contexto actual, en otras palabras el “this” es en este caso, como si se hiciera referencia a la clase que deriva de GameCanvas. Este es el enlace para que se “escuchen” los comandos dentro de la clase EjemploGameCanvas, esa instrucción va en el constructor de la clase, como se verá más adelante.
La interfaz CommandListener, tiene un único método que se llama CommandAction, algo parecido con la interfaz Runnable que tiene a su único método llamado Run().
El método CommandAction, me permite saber que comando se ha presionado, el método lleva dos parámetros como se observa:
public void commandAction(Command command, Displayable displayable) {
//Código para decodificar las acciones del Command
}
Uno de los parámetros es llamado “command” contiene el comando que se ha presionado, recuerde puede haber varios “Commands”, con este parámetro sabremos cual es el presionado, el otro parámetro indica en que pantalla se ha presionado el comando, que en este ejemplo no es relevante.
Aquí se hace un paréntesis para saber cómo se agrega el botón físicamente al GameCanvas, para agregar un botón o comando se usa la clase Command, haciendo uso de esta clase fácilmente se puede crear un objeto Command, el constructor para hacerlo es así:
Command (Etiqueta, tipo_de_comando, prioridad)
El primer parámetro lleva una etiqueta o palabra que parecerá en el celular como nombre del comando, la etiqueta es importante porque es la que el usuario del programa ve cuando ejecuta la aplicación, el siguiente parámetro especifica el tipo de comando, esto se vio ya en un post anterior como se mencionó arriba, el último parámetro indica la prioridad en que se desplegará el comando en el teléfono, por que puede haber más de un objeto Command, este último parámetro es un número entero.
Un ejemplo para la creación de un objeto Command sería así:
Command cmd = New Command(“Salir”, Command.Exit, 1);
El objeto se llama cmd, el usuario verá “salir” en el teléfono, al presionarlo se cierra la aplicación por que el Command es de tipo “Exit”.
Aún así la sentencia anterior no muestra ningún comando en la pantalla, este tiene que agregarse al Canvas, esto se logra fácilmente con el método
addCommand( Command cmd)
El método en verdad agrega el comando al GameCanvas, lleva como parámetro precisamente un objeto del tipo Command, esto es bueno pues así nos evita declarar la variabla “cmd” vista hace rato, entonces es posible agregar el comando al GameCanvas así:
addCommand ( new Command("Regresar", Command.OK, 1));
El addCommand, se agregan por lo general en el constructor que es el primer código que se ejecuta de la clase, así que la clase completa va viéndose así:
public class EjemploGameCanvas extends GameCanvas implements Runnable, CommandListener{
Graphics g;
public EjemploGameCanvas () {
super(true); // código del constructor
setCommandListener(this);
addCommand ( new Command("Regresar", Command.OK, 1));
g = getGraphics();
Thread subproceso = new Thread(this);
subproceso.start();
}
public void run() {
// pantalla en negro
g.setColor(0x000000);
g.fillRect(0, 0, getWidth(), getHeight());
// dibujo de las letras “hola mundo…
g.setColor(0xff00FF);
g.drawString("Hola mundo, con GameCanvas", 0, 60, Graphics.LEFT || Graphics.TOP);
flushGraphics();
}
//Clase que detecta los comandos
public void commandAction(Command command, Displayable displayable) {
//código que detecta el comando
}
}
Como agregar el código al método commandAction
Finalmente se debe agregar el código al método commandAction, cada que es presionado el botón, se ejecuta este código, el código primero se “fija” cuál es el comando presionado, esto pensando en que puede haber varios botones, el método que me indica cual botón se presiono es llamado getCommandType, y es un método de la clase Command, así se puede detectar el botón presionado
if(command.getCommandType() == Command.OK) {
// se ejecuta elcódigo cuando se presiona el okCommand
}
Justo al presionar este botón, se tiene que mostrar la pantalla con la interfaz de alto nivel, para hacerlo se usa la clase Display, usando además la variable que hacer referencia al MIDlet “hellomidlet” esto se logra así:
Esté método se agrega dentro del if anterior y listo se termina el ejercicio, el código completo se muestra enseguida. Al final se observa donde se ubica la instrucción anterior:
import javax.microedition.lcdui.*;
public class EjemploGameCanvas extends GameCanvas implements Runnable, CommandListener{ HelloMIDlet hellomidlet; Graphics g; // objeto gráfico public EjemploGameCanvas (HelloMIDlet hm) { super(true); // código del constructor hellomidlet = hm; setCommandListener(this); addCommand(new Command("Regresar", Command.OK, 1)); g = getGraphics(); Thread subproceso = new Thread(this); subproceso.start(); } public void run() { // pantalla en negro g.setColor(0x000000); g.fillRect(0, 0, getWidth(), getHeight()); // dibujo de las letras “hola mundo… g.setColor(0xff00FF); g.drawString("Hola mundo, con GameCanvas", 0, 60, Graphics.LEFT || Graphics.TOP); flushGraphics(); } public void commandAction( Command cmd, Displayable displayable) { if (cmd.getCommandType()== Command.OK) Display.getDisplay(hellomidlet).setCurrent(hellomidlet.getForm()); } }
Bueno con estos e termina el post, pero fiel a mi costumbre, para evitar dudas de donde se ubica el código y todo eso, aqui les dejo el video-tutorial, guiandose con el, no debe haber dudas de ningún tipo.