Kdo si J2ME, nezlobí – menu
Aplikace se nám začíná komplikovat, takže je načase přidat menu, které bude tvořit výchozí obrazovku a pomáhat uživateli s orientací v možnostech programu. A co takhle jich rovnou udělat víc, abychom měli z čeho vybírat?
Jednoduché menu
Nejsnazší je použít k tvorbě menu třídu javax.microedition.lcdui.List
. K tomu potřebujeme nejprve vytvořit ikony k jednotlivým položkám seznamu a vymyslet, jak se budou tyto položky jmenovat. Je dobré dodržovat nějaké konvence, aby uživatel našel pod každým názvem vždy to, co očekává. Při vývoji aplikace na různá zařízení a pro různé operátory může trochu komplikovat život, že někteří výrobci a operátoři mají celkem podrobný popis svých konvencí a doporučení a jednotlivé popisy mohou mít protichůdné požadavky.
Aby to bylo ještě trochu složitější, mají také různé telefony odlišnou maximální velikost ikon seznamu. Velikost těchto ikon se někdy dá najít v dokumentaci, ale občas je nutné se prostě pokusit spočítat počet pixelů ikony v obrázku přímo na telefonu a takto získaný výsledek doladit metodou „pokus – omyl“. V našem případě (Nokia řady 40) je odpovídající velikost 16×16 pixelů.
Pro texty položek zatím kvůli jednoduchosti zavedeme řetězcové konstanty. Je dobrým zvykem, že jména konstant obsahují pouze velká písmena. Jsou-li složena z více slov, oddělíme tato slova podtržítkem.
Seznam bude typu javax.microedition.lcdui.List.IMPLICIT
. To znamená, že když uživatel vybere nějakou položku seznamu, zavolá aplikační manažer metodu commandAction(Command prikaz, Displayable zobrazitelnaKomponenta)
příslušného posluchače událostí. Parametr prikaz
této metody bude obsahovat abstraktní příkaz javax.microedition.lcdui.List.SELECT_COMMAND
, což nás ale zrovna vůbec nezajímá. Kterou položku seznamu uživatel vybral, zjistíme porovnáním textu vybrané položky s našimi textovými konstantami.
public class MenuList extends List implements CommandListener {
// texty položek menu
public static final String PLAY = „Hrát“;
public static final String HELP = „Nápověda“;
public static final String EXIT = „Konec“;
public MenuList(){
super(„“, List.IMPLICIT);
try{
// inicializace obrázků
Image playImg = Image.createImage(„/playIco.png“);
Image helpImg = Image.createImage(„/helpIco.png“);
Image exitImg = Image.createImage(„/exitIco.png“);
// přidání obrázků do seznamu
this.append(PLAY, playImg);
this.append(HELP, helpImg);
this.append(EXIT, exitImg);
} catch (Exception e){
}
// nastavení posluchače událostí
this.setCommandListener(this);
}
/* metoda rozhraní CommandListener */
public void commandAction(Command c, Displayable d) {
// zjištění indexu vybrané položky seznamu
int i = this.getSelectedIndex();
// zjištění jména vybrané položky seznamu
String s = this.getString(i);
GameMIDlet midlet = GameMIDlet.getInstance();
// vykonání akce odpovídající vybrané položce
if(s == PLAY){
midlet.playAction();
}else if(s == HELP){
midlet.helpAction();
}else if(s == EXIT){
midlet.destroyApp(true);
}
}
}
Výsledek bude na emulátoru Nokia 6230 na Linuxu vypadat takto:
Menu – emulátor Nokia 6230
Myslíte-li si, že je na obrázku ve slově Nápověda překlep, musím vás zklamat. Takto prostě vypadá čeština na některých emulátorech. Skutečné telefony mají občas s některými českými písmeny sice také problémy, ale ne při tomto způsobu práce s texty. Problémy dělá například načítání diakritiky z deskriptoru aplikace.
Je však stále lepší používat emulátor cílového telefonu se špatnou češtinou, než vlastní skin tohoto telefonu pro J2MEWTK. V J2MEWTK u skinu nelze nastavit velikost ikon v seznamu a výsledek se správnou velikostí pro Nokii řady 40 pak vypadá následovně:
Menu – J2MEWTK
Nízkoúrovňové menu
Při použití třídy javax.microedition.lcdui.Canvas
k tvorbě menu máme široké možnosti, co do určení výsledného vzhledu tohoto menu. Jediné, co nás bude omezovat, je naše představivost, velikost aplikace a velikost a počet barev displeje. V tomto článku si ukážeme jednu z mnoha možností, ale přístup je vždy podobný, nezávisle na konkrétním vzhledu. Naše grafické menu bude vypadat takto:
Grafické menu
K tomuto menu potřebujeme dva obrázky – obrázek pozadí a obrázek položek menu s průhledným pozadím. Při vykreslování menu nakreslíme nejprve pozadí, pak žlutý pruh zvýrazňující vybranou položku a nakonec seznam položek. Budeme odchytávat stisky kláves. Při stisku šipky nahoru nebo dolu změníme zvýrazněnou položku, při vybrání položky zavoláme odpovídající akci.
public class MenuCanvas extends Canvas {
// obrázek na pozadí
private Image background;
// obrázek s položkami menu
private Image menu;
// index vybrané položky
private int selected = 0;
// barva zvýrazňovacího pruhu
private int selectedColor = 0xfff38a;
// výška zvýrazňovacího pruhu
private int itemHeight = 25;
// umístění levého horního rohu obrázku
// s položkami menu
private int menuY;
private int menuX;
// umístění levého horního rohu obrázku
// s pozadím
private int bgX;
private int bgY;
// počet položek menu
private int menuItems = 3;
public MenuCanvas(){
try{
// inicializace obrázků
background = Image.createImage(„/menubg.png“);
menu = Image.createImage(„/menu.png“);
} catch (Exception e){
}
/* nastavení umístění levého horního rohu
* pozadí a obrázku s položkami menu tak,
* aby tyto obrázky byly na displeji vycentrovány
*/
menuX = (getWidth() – menu.getWidth())/2;
menuY = (getHeight() – menu.getHeight())/2;
bgX = (getWidth() – background.getWidth())/2;
bgY = (getHeight() – background.getHeight())/2;
}
/* vykreslení menu */
protected void paint(Graphics g) {
// překreslení celého displeje bílou barvou
g.setColor(0xffffff);
g.fillRect(0,0,getWidth(), getHeight());
// nakreslení pozadí
g.drawImage(background, bgX, bgY,
Graphics.TOP | Graphics.LEFT);
// nakreslení žlutého pruhu
g.setColor(selectedColor);
g.fillRect(0, menuY + selected * itemHeight,
getWidth(), itemHeight);
// nakreslení položek menu
g.drawImage(menu, menuX, menuY,
Graphics.TOP | Graphics.LEFT);
}
protected void keyPressed(int key) {
int action = getGameAction(key);
switch(action){
case Canvas.UP: // pohyb kurzorem nahoru
selected = Math.abs((–selected)%menuItems);
repaint();
break;
case Canvas.DOWN: // pohyb kurzorem dolů
selected = (++selected)%menuItems;
repaint();
break;
case Canvas.FIRE: // vybrání položky
GameMIDlet midlet=GameMIDlet.getInstance();
if(selected==0){
midlet.playAction();
} else if(selected==1){
midlet.helpAction();
} else if(selected==2){
midlet.destroyApp(true);
}
}
}
}
Jak jste si jistě všimli, obsahuje třída MenuCanvas
některé parametry, které mohou být závislé na velikosti displeje nebo na konkrétní aplikaci a které by se hodilo nastavovat beze změny kódu. Jsou to barva zvýrazňovacího pruhu (selectedColor
) a výška zvýrazňovacího pruhu (itemHeight
). Takovéto parametry aplikace lze například načítat z deskriptoru aplikace pomocí metody getAppProperty(String key)
třídy javax.microedition.midlet.MIDlet
. Tento přístup však nelze použít vždy, protože některé portály sloužící ke stahování aplikací na mobilní telefony umožňují vložit do deskriptoru pouze několik předdefinovaných povolených atributů. (Načítání z datových souborů necháme na jiný článek.)
Které menu použijeme?
Máme teď vytvořeny dvě implementace menu aplikace a chtěli bychom s co nejmenší námahou vyměnit menu, jež je v aplikaci použito. Rozhodně nechceme kvůli výměně menu měnit zdrojový kód a aplikaci znovu překládat. Dáme si tedy jméno třídy, kterou pro menu použijeme, do deskriptoru aplikace jako atribut a vytvoříme instanci této třídy podle jejího jména.
// získání jména implementace menu z deskriptoru aplikace
String className = this.getAppProperty(„menu-class“);
if(className==null){
className = „MenuList“;
}
try{
// vytvoření instance třídy se jménem className
menu = (Displayable)Class.forName(className).newInstance();
} catch (Exception e){
}
Teď nám k výměně menu stačí pouze změnit obsah atributu menu-class
v deskriptoru aplikace a v JAR souboru vyměnit jednu třídu za jinou.
Jedináček neboli singleton
Aby byla aplikace přehledná, umístila jsem základní mechanismus, který řídí přechody mezi obrazovkami aplikace, do třídy GameMIDlet
. Hra zatím obsahuje obrazovky menu, nápověda a vlastní hra. Třída GameMIDlet
proto obsahuje pro přechod na každou z obrazovek odpovídající metodu (menuAction()
, helpAction()
a playAction()
).
Třída GameMIDlet
je typickým představitelem třídy, která v rámci aplikace existuje právě v jedné instanci. Tento návrhový vzor bývá nazýván jedináček nebo singleton (podle toho, zda je dotyčný zastáncem české nebo anglické terminologie). Jelikož má tedy třída GameMIDlet
pouze jednu instanci, nemusíme ji ostatním třídám předávat jako parametr. Uložíme si odkaz na tuto instanci do statické proměnné instance
a zpřístupníme ji statickou metodou getInstance()
.
Ke stažení
Veškeré zde uvedené zdrojové kódy, obrázky ke hře a hotovou aplikaci si můžete stáhnout a použít pro vlastní potřebu.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
inPage AI: Jak na generování obsahu
18. července 2024 -
Aktualizujete svoji .NET webovou aplikaci? Může se hodit app_offline.htm
10. července 2024
Nejnovější
-
Jak se chránit před podvody na internetu – část 2
14. října 2024 -
Doména .io v ohrožení: Co přinese předání Čagoských ostrovů?
10. října 2024 -
Jak se chránit před podvody na internetu – část 1
8. října 2024