MIDlet GUI, a Canvas
dátum: 2007-12-14
Kategóriák:
Java/J2ME
A grafikus felhasználói interfész 2 szintre osztható:
- Magas és
- Alacsony szintre.
A magas szint? GUI attól magas szint?, hogy az alap képerny?elemeket (mint pl. jelöl? lista, szöveg beviteli mez?, stb.) nem nekünk kell implementálnunk a nulláról, hanem készen felhasználhatók, egy egyszer? osztályhierarchiára tagolva a javax.microedition.lcdui csomagban. A hagyományos java.lang.Object-t?l származtatva a Displayable osztály az összes, egész ablakot reprezentáló képerny?elemek ?se. Az eszköz képerny?ét a Display objektum reprezentálja (ezen keresztül "hozható a kijelz?re" az aktuális Displayable leszármazott, de emellett a telefon rezgését is ki/be kapcsolhatjuk, a kijelz? háttérfényét is szabályozhatjuk sok egyéb mellett). A Displayable objektummal egy szinten áll a Command osztály a hierarchiában, ami a magas szint? eseménykezelés egyik résztvev?je: attól magas szint?, hogy valamely Displayable leszármazotthoz adva, nem kell a megjelenítéssel, esemény detektálással bajlódnunk, a telefon automatikusan lekezeli a parancs típusától függ?en, hogy melyik vezérl?billenty? lenyomására keletkezzen. Nekünk csak egy eseményfigyel?t kell adnunk az aktuális Displayable leszármazotthoz, és az továbbítja a keletkezett eseményt a feldolgozáshoz (Fontos megjegyezni, hogy csak egy eseménykezel? szál van, így Deadlock is kialakulhat, ha pl. olyan m?veletet végzünk egy esemény lekezelésénel, ami felhasználói meger?sítést kezdeményez, pl. egy hálózati kapcsolat megnyitása). Célszer? alaposan megtervezni egy optimáls szálkezelést ennek kivédésére.
A magas szint? elemekr?l, így a Commandról is majd legközelebb írok.
A Displayable osztálynak két közvetlen leszármazottja van:
- Canvas és
- Screen.
Az els? egy absztrakt osztály, ami a már említett alacsony szint? képerny?kezelésért felel?s, teljes képerny?s módra állítható, lehet?séget ad a billenty? események lekezelésére, és a paint(Graphics g) védett eljárását megvalósítva, lehet?ségünk van egyszer? grafikus felülettel rendelkez? jétékokat írni (komplexebb dolgokra a GameCanvas való, ami Sprite és réteg kezeléssel könnyíti a dolgunk).A Graphics osztály nagyban hasonlít a JavaSE csomagban lév?höz, de van néhány kisebb eltérés (ne felejtsd el böngészni az apidocot: http://java.sun.com/javame/reference/apis/jsr118/).
A billenty?kezelés int konstansok segítségével történik:
- KEY_NUM0 ... KEY_NUM9: számbillenty?k,
- KEY_STAR: csillag gomb,
- KEY_POUND: hashmark (azaz kett?skereszt),
- UP,DOWN,LEFT,RIGHT: iránybillenty?k (játékbillenty?nek min?sülnek),
- FIRE: t?z billenty?, és a
- GAME_A ... GAME_D: "játék gombok" (általában 1,3,7,9 gombok). Utóbbi három gombtípust a getGameAction(int keyCode) függvény segítségével szokás azonosítani, a többit a keyCode alapján.
A lenyomott gombot a következ? 3 eljárással kezeletjük le:
- keyPressed(int keyCode)
- keyReleased(int keyCode)
- keyRepeated(int keyCode).
Ezek mellett lehet?ségünk van a pointer lekezelésére is érint?képerny?s telefonon a következ? függvényekkel:
- pointerDragged(int x, int y)
- pointerPressed(int x, int y)
- pointerReleased(int x, int y).
itt egy példa, aminél egy piros kört mozgathatunk a képerny?n:
package simplecanvas;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
/**
* @author Szebeni
*/
public class SimpleMidlet extends MIDlet {
private SimpleCanvas myCanvas;
private SimpleCanvas getCanvas(){
if (myCanvas==null){
myCanvas=new SimpleCanvas(this);
}
return myCanvas;
}
public void startApp() {
Display.getDisplay(this).setCurrent(getCanvas());
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void exitMIDlet() {
Display.getDisplay(this).setCurrent(null);
destroyApp(true);
notifyDestroyed();
}
}
class SimpleCanvas extends Canvas{
private int max_height=getHeight();
private int max_width=getWidth();
private int pos_x=max_width/2;
private int pos_y=max_height/2;
private int backgroundColor=0xffffff;
private int borderColor=0x000000;
private int color=0xff0000;
private int fontColor=0x0000ff;
private Font font=Font.getFont(Font.FACE_MONOSPACE,
Font.STYLE_ITALIC | Font.STYLE_BOLD, Font.SIZE_MEDIUM);
private int d=50;
private SimpleMidlet m;
SimpleCanvas(SimpleMidlet m_) {
super();
m=m_;
}
protected void keyReleased(int arg0) {
int gameAction=getGameAction(arg0);
switch (gameAction){
case Canvas.UP:
if (pos_y>0)
--pos_y;
break;
case Canvas.DOWN:
if (pos_y<max_height-d)
++pos_y;
break;
case Canvas.RIGHT:
if (pos_x<max_width-d)
++pos_x;
break;
case Canvas.LEFT:
if (pos_x>0)
--pos_x;
break;
}
if (arg0 == Canvas.KEY_STAR)
m.exitMIDlet();
else
repaint();
}
protected void keyRepeated(int arg0) {
keyReleased(arg0);
}
protected void paint(Graphics g) {
g.setColor(backgroundColor);
g.fillRect(0, 0, max_width, max_height);
g.setColor(borderColor);
g.fillArc(pos_x-1, pos_y-1, d+2, d+2, 0, 360);
g.setColor(color);
g.fillArc(pos_x, pos_y, d, d, 0, 360);
g.setColor(fontColor);
g.setFont(font);
g.drawString("Exit: *", 10, 10, g.TOP | g.LEFT);
}
}
A forrás magyarázata:
Az aktuális képerny? legyen a vásznunk a program indulása után:
public void startApp() {
Display.getDisplay(this).setCurrent(getCanvas());
}
Kilépés folyamata:
- vászon "levétele" a kijelz?r?l
- er?források felszabadítása
- az AMS értesítése a terminálásról
public void exitMIDlet() {
Display.getDisplay(this).setCurrent(null);
destroyApp(true);
notifyDestroyed();
}
Adatok a rajzoláshoz:
- a kijelz? méretei
- aktuális pozíció a rajz bal fels? sarkához
private int max_height=getHeight();
private int max_width=getWidth();
private int pos_x=max_width/2;
private int pos_y=max_height/2;
Színek a rajzoláshoz:
- RGB modell szerint hexadecimálisan
- fehér: 0xffffff
- fekete: 0x000000
private int backgroundColor=0xffffff;
private int borderColor=0x000000;
private int color=0xff0000;
private int fontColor=0x0000ff;
Bet?típus a szöveg kiírásához:
- 1. paraméter: FACE_MONOSPACE, FACE_PROPORTIONAL vagy FACE_SYSTEM
- 2. paraméter: STYLE_BOLD, STYLE_ITALIC, STYLE_UNDERLINED, STYLE_PLAIN vagy ezek bináris kombinációja
- 3. paraméter: SIZE_SMALL, SIZE_MEDIUM, vagy SIZE_LARGE
private Font font=Font.getFont(Font.FACE_MONOSPACE,
Font.STYLE_ITALIC | Font.STYLE_BOLD, Font.SIZE_MEDIUM);
Átmér? a körhöz, valamint azért kell átadni a midlet példányunkat, hogy elérhet? legyen az exitMIDlet() függvénye a kilépéshez.
private int d=50;
private SimpleMidlet m;
SimpleCanvas(SimpleMidlet m_) {
super();
m=m_;
}
Gombok felengedésének lekezelése, billenty?kódhoz meghatározzuk a játék akciót, majd értelemszer?en módosítjuk az aktuális pozíciót úgy, hogy a kör ne lépjen le a kijelz?r?l.
protected void keyReleased(int arg0) {
int gameAction=getGameAction(arg0);
switch (gameAction){
case Canvas.UP:
if (pos_y>0)
--pos_y;
break;
case Canvas.DOWN:
if (pos_y<max_height-d)
++pos_y;
break;
case Canvas.RIGHT:
if (pos_x<max_width-d)
++pos_x;
break;
case Canvas.LEFT:
if (pos_x>0)
--pos_x;
break;
}
Kilépés lekezelése, ha csillagot nyomott a felhasználó, akkor terminálás, különben pedig a képerny? ujrarajzolása.
if (arg0 == Canvas.KEY_STAR)
m.exitMIDlet();
else
repaint();
Ezzel a kis programrésszel le lesz kezelve, ha nyomva tartja a felhasználó a gombot.
protected void keyRepeated(int arg0) {
keyReleased(arg0);
}
Végül a lényeg, a rajzolás:
- Kijelz? törlése a háttérszínnel
- Nagyobb kör rajzolása, keretként
- piros kör a kereten belülre
- szöveg kiiratása adott bet?típussal, színnel.
protected void paint(Graphics g) {
g.setColor(backgroundColor);
g.fillRect(0, 0, max_width, max_height);
g.setColor(borderColor);
g.fillArc(pos_x-1, pos_y-1, d+2, d+2, 0, 360);
g.setColor(color);
g.fillArc(pos_x, pos_y, d, d, 0, 360);
g.setColor(fontColor);
g.setFont(font);
g.drawString("Exit: *", 10, 10, g.TOP | g.LEFT);
}
Legközelebb a magas szint? GUI-ról írok. Addigis szívesen várom a véleményeket akár privátban, akár a vitafórumban.
