21.03 High-Level vs. Low-Level GUI
Es gibt zwei grundlegend verschiedene Wege in der Java ME Welt um grafische Oberflächen darzustellen: Low-Level und High-Level GUIs. In diesem Kapitel lernen Sie die Grundlagen beider Techniken und wann Sie welche einsetzen. Die nachfolgenden Kapitel liefern dann detailliertere Informationen zu den jeweiligen Architekturen.
High-Level vs. Low-Level GUI
Der Hauptunterschied zwischen High-Level und Low-Level liegt darin, dass Sie bei der Programmierung einer High-Level GUI auf fertige Komponenten wie z. B. einer Auswahlliste (javax.microedition.lcdui.List
), einer Texteingabe (javax.microedition.lcdui.TextField
) oder einen Container, der mehrere Komponenten enthält (javax.microedition.lcdui.Form
) zugreifen, während Sie bei einer Low-Level Architektur alles selbst zeichnen müssen/können. Beides hat seine Vor- und Nachteile.
Vorteile High-Level
- Einfacher und schneller zu entwickeln – Es müssen lediglich fertige Komponenten eingebunden werden.
- Robust, fehlerunanfälliger und an das Design des Geräts angepasst – Die Darstellung und Implementierung wird vom Endgerät übernommen.
- Sehr hohe Portabilität – In nur sehr wenigen Fällen muss gerätespezifisch programmiert werden, wodurch meistens viele Geräte mit einer einzigen Applikation versorgt werden können.
Nachteile High-Level
- Design – Das Aussehen der High-Level Komponenten wird fast vollständig vom Endgerät bestimmt und ist somit fast nicht beeinflussbar.
- Geringe Flexibilität – High-Level Objekte können nur sehr begrenzt angepasst oder erweitert werden.
- Schwer erweiterbar – Wenn Sie selbst neue Komponenten programmieren wollen, ist dies nur mit sehr viel Aufwand möglich.
Vorteile Low-Level
- Sehr hohe Flexibilität – Sie können Ihre Low-Level Komponenten nach Belieben erweitern, anpassen und neu erstellen.
- Freiheit im Design – Low-Level GUIs sehen genau so aus, wie Sie sie programmieren – Sie können alles beeinflussen.
- Dynamisch und animiert – Es ist problemlos möglich, dynamische und animierte Komponenten zu erzeugen.
Nachteile Low-Level
- Keine Basis-Komponenten – Sie müssen wirklich alles selbst zeichnen, was in vielen Fällen (bspw. Textfelder) nur unter erheblichem Aufwand möglich ist.
- Geringe Portabilität – Da Sie die Darstellung übernehmen, kommt es oftmals vor, dass Sie sehr viele Applikationen für unterschiedliche Geräte ausliefern müssen, um bspw. auf die richtige Displaygröße oder Tasten zu reagieren.
- Fehleranfälligkeit – Durch teilweise auftretende Ungereimtheiten und Kompatibilitätsprobleme zwischen den Geräten wird Ihr Code auch fehleranfälliger.
Zusammenfassend lässt sich sagen, dass für Spiele eher die Low-Level API und für Applikationen die High-Level API in Frage kommt. Natürlich gibt es auch hier Ausnahmen und in manchen Fällen ist es sogar sinnvoll, beide Darstellungsformen miteinander zu mischen.
Grundlagen der GUI-Programmierung in Java ME
Dennoch haben beide Techniken eine Sache gemeinsam: Damit Sie dargestellt werden können, müssen Sie von der Klasse javax.microedition.lcdui.Displayable
erben bzw. einer Klasse hinzugefügt werden, welche von javax.microedition.lcdui.Displayable
erbt, und dieses Hinzufügen erlaubt (High-Level). Erst bei der Spezialisierung trennen sich die Wege – Ein javax.microedition.lcdui.Canvas
ist die Grundlage für eine Low-Level GUI und ein javax.microedition.lcdui.Screen
für eine High-Level GUI.
Displayable
ist folglich die Hauptklasse/Wurzel aller grafischen Elemente. Ein Displayable
wird direkt auf dem Handydisplay dargestellt. Hierzu müssen Sie sich eine Referenz auf das javax.microedition.lcdui.Display
des Endgeräts beschaffen, und dieses Display
anweisen, Ihre Displayable
-Klasse anzuzeigen:
public void showDisplayable(Displayable disp, MIDlet mid) { Display display = Display.getDisplay(mid); display.setCurrent(disp); }
Durch die gemeinsame Basisklasse Displayable
gibt es Operationen, die Sie sowohl für eine High-Level, als auch für eine Low-Level Architektur verwenden können.
Command
Im Java ME Einstiegskapitel haben Sie bereits die Funktion addCommand
und die Klasse javax.microedition.lcdui.Command
kennengelernt. Mit dieser können Sie ein einfaches Menü implementieren – sowohl für High- als auch für Low-Level GUIs. Dieses Menü wird geräteabhängig angezeigt, meistens den Softkeys zugeordnet und ermöglicht somit eine gerätespezifische, intuitive Steuerung.
Softkeys sind in diesem Fall Tasten, die nicht zur Standard-Handytastatur gehören und sich meistens direkt unter dem Display des Handys befinden. Softkeys können somit auf einem anderen Weg nicht pauschal in Java ME abgefragt werden.
Ein Command
besteht aus einem Kurztext (bspw. „Berechne“), einem längeren Text (bspw. „Berechne Formel“), einer Orientierung/Typ und einer Priorität. Je nach verfügbarem Platz wird entweder der Langtext oder der Kurztext angezeigt. Die Orientierung spezifiziert, wo das Command
angezeigt werden soll – bspw. dort, wo sich am Telefon normalerweise der OK oder der Beenden-Button befindet. Folgende Werte sind möglich: Command.BACK, Command.CANCEL, Command.EXIT, Command.HELP, Command.ITEM, Command.OK, Command.SCREEN
und Command.STOP
. Die Priorität legt fest, an welcher Stelle das Command
angezeigt wird, falls einem Typ mehrere Commands
zugeordnet wurden.
Um ein Command
anzuzeigen, muss die Methode addCommand(Command cmd)
der Klasse Displayable
aufgerufen werden. Genauso kann über der removeCommand(Command cmd)
ein Command
wieder entfernt werden.
Command help = new Command("Help", Command.HELP, 1); Command about = new Command("About", "About my cool MIDlet", Command.HELP, 2); Command cancel = new Command("Cancel", Command.CANCEL, 1); disp.addCommand(help); disp.addCommand(about); disp.addCommand(cancel);
Damit Sie auf eine Command
-Eingaben reagieren können, müssen Sie über setCommandListener(CommandListener cl)
der Displayable
-Klasse einen CommandListener
hinzufügen. Ein CommandListener
muss die Methode commandAction(Command c, Displayable d)
implementieren. Falls auf ein Command
geklickt wurde, wird die Methode mit dem betätigten Command
und dem beinhaltenden Displayable
aufgerufen.
Beachten Sie, dass Sie keine Commands
verwenden sollten, wenn Sie eine Low-Level GUI (Canvas
) im Vollbildmodus (setFullScreenMode(true)
) einsetzen.
Ticker
Wenn Sie einen Lauftext auf dem Bildschirm anzeigen möchten, können Sie die Methode setTicker(Ticker ticker)
verwenden. Der Inhalt des javax.microedition.lcdui.Tickers
wird dann geräteabhängig als Lauftext auf dem Display angezeigt. Über new Ticker(String text)
können Sie einen Ticker mit dem spezifischen Text erzeugen.
Sonstige Standardmethoden
Ansonsten verfügt Displayable
über Standardmethoden. Mit getHeight()
erhalten Sie die Höhe der Displayable
, mit getWidth()
die Breite. isShown()
gibt true
zurück, falls das Displayable
gerade angezeigt wird. Und letztendlich können Sie über setTitle(String title)
einen Text/Namen für die aktuelle Anzeige vergeben bzw. diesen auch wieder über getTitle()
abfragen.
Images
Bilder können Sie übrigens sowohl auf High- als auch auf Low-Level GUIs anzeigen. Hierzu wird die Klasse Image
verwendet. Ein neues Image
erzeugen Sie über den statischen Aufruf Image.createImage("/path/to/image.png");
. Dabei muss das Bild direkt in der JAR-Datei liegen (in diesem Beispiel unter path/to und mit dem Namen image.png).
Es bietet sich an, ausschließlich PNG-Bilder zu verwenden. Dieses Format wird von sehr vielen Java ME Geräten unterstützt.
Ihr Bild können Sie so wie normalen Text auf bspw. einer Form anzeigen:
Image img = Image.createImage("/path/to/image.png"); Form f = new Form("MyForm"); f.append(img); Display.getDisplay(this).setCurrent(f);
Zusammenfassung
Zum Abschluss und als kleine Zusammenfassung können Sie sich noch ein kleines MIDlet – basierend auf unserem High-Level Hello-World-MIDlet aus dem Einstiegskapitel ansehen:
package de.jbb.dispTest; 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.Ticker; import javax.microedition.midlet.MIDlet; public class DispTest extends MIDlet implements CommandListener { private boolean firstTime = true; private Display disp; private Form form; private Command exit; private Command showHeight; private Command showWidth; private Command showTicker; private Command hideTicker; public void startApp() { if (firstTime) { disp = Display.getDisplay(this); form = new Form("Displayable Test"); exit = new Command("Beenden", Command.EXIT, 1); showHeight = new Command("Höhe anzeigen", Command.SCREEN, 1); showWidth = new Command("Breite anzeigen", Command.SCREEN, 2); showTicker = new Command("Ticker einblenden", Command.SCREEN, 3); hideTicker = new Command("Ticker ausblenden", Command.SCREEN, 4); form.addCommand(exit); form.addCommand(showHeight); form.addCommand(showWidth); form.addCommand(showTicker); form.addCommand(hideTicker); form.setCommandListener(this); firstTime = false; } disp.setCurrent(form); } public void commandAction(Command c, Displayable d) { if (c == exit) { destroyApp(false); } else if (c == showHeight) { form.deleteAll(); form.append("Höhe: " + form.getHeight()); } else if (c == showWidth) { form.deleteAll(); form.append("Breite: " + form.getWidth()); } else if (c == showTicker) { form.setTicker(new Ticker("Hallo, Hallo ich bin ein Ticker")); } else if (c == hideTicker) { form.setTicker(null); } } public void destroyApp(boolean unconditional) { notifyDestroyed(); } public void pauseApp() {} }
Nachfolgend werden High-Level und Low-Level GUI Programmierung soweit möglich in separate Kapitel aufgeteilt.