Einbindung der Tastatur Auch die Tastatur kann man wie die Maus zur interaktiven Programmsteuerung verwenden. Bei der Maus ist stets klar, welche grafische Komponente bei einem Klick oder einer Bewegung gemeint ist; es ist die, in der sich der Mauszeiger befindet. Natürlich möchte man, dass ein Tastaturbefehl auch nur eine bestimmte Komponente anspricht. Wenn nämlich ein Tastaturbefehl bei mehreren Fenstern eine Reaktion auslösen kann, so könnten in Fenstern von nicht gemeinten Anwendungen ungewollte Reaktionen ausgelöst werden. So bewirkt die Tastenkombination CONTROL C bei den meisten Programmen den sofortigen Abbruch. Im Allgemeinen will man damit aber nicht alle laufenden Programme stoppen, sondern nur ein bestimmtes. Um das gerade beschriebene Verhalten zu verhindern, gibt es zu jedem Zeitpunkt höchstens eine grafische Komponente, zu der Tastatureingaben weitergeleitet werden. Man sagt diese Komponente habe den Fokus. Hat eine Fenster oder eine seiner Unterkomponenten den Fokus, so erkennt man dies bei fast allen Betriebssystemen an der farblich hervorgehobenen Titelleiste. Hat ein Knopf den Fokus, so erkennt man das je nach Betriebssystem an eine einer anderen Farbe, an einem dickeren Umriss oder einer stärkeren Schattierung. Bei editierbaren Textkomponenten erkennt man an einer blinkenden Einfügemarke (oder am Vorhandensein der Einfügemarke), in welcher bei einem Tastendruck der Text erscheint. Durch Anklicken einer anderen Komponente mit der Maus (Windows) oder beim Hineinbewegen des Mauszeigers (UNIX) verschiebt man den Fokus auf diese. Oft kann man auch mit der Tabulator-Taste den Fokus von einer Komponenten zu nächsten weiter schieben. Einige Swing-Komponenten können den Fokus per Voreinstellung nicht erlangen, weil diese nur sehr selten durch die Tastatur gesteuert werden. Die Entwickler von JAVA wollen damit verhindern, dass beim Weiterschalten mit der Tabulator-Taste der Fokus unnötigerweise auf Komponenten wandert, die im Allgemeinen nicht tastaturgesteuert sind. Zu den Komponenten, die den Fokus per Voreinstellung nicht erlangen können, gehören Label und Panels. Jede grafische Komponente von Swing erbt von der Stammklasse JComponent die Methode public boolean isfocustraversable(). Diese Methode wird zur Laufzeit abgefragt, wenn eine Komponente den Fokus erhalten soll. Liefert sie dann true, so erhält die Komponente den Fokus, liefert sie false so bleibt der Fokus dort, wo er war. Will man das Verhalten einer Komponente bezüglich des Fokus ändern, so leitet man eine Klasse von dieser 1
Komponente ab, und überschreibt dort die Methode isfocustraversable. Das folgende Programmfragment erlaubt, dass die Komponente den Fokus erhält. Um das zu verbieten, ändert man den Rückgabewert auf false. public boolean isfocustraversable() return(true); Um einer Komponente den Fokus zuzuweisen (und ihn damit einer anderen zu entziehen) benutzt man die Methode requestfocus. Diese ist in der Stammklasse JComponent definiert und damit in allen grafischen Komponenten von Swing verfügbar. Um den Fokus auf eine Komponente Komp zu übertragen, benutzt man den Befehl Komp.requestFocus(); Wir wollen nun eine Anwendung entwickeln, die das gerade gesagte verdeutlicht. In einen Rahmen kleben wir ein Panel und eine rollbare Text-Area untereinander ein. Das Panel soll in der Lage, sein Tastatureingaben zu empfangen. Die Text-Area darunter soll die gedrückte Taste anzeigen. Wie oben gesagt, muss das Panel den Fokus haben, um Tastatureingaben erhalten zu können. Dazu legen wir fest, dass das Panel den Fokus hat, wenn sich der Mauszeiger im dem Panel befindet. Ist er außerhalb, so hat die Text-Area den Fokus. Um das gerade beschriebene Verhalten zu implementieren, verwenden wir zwei Aufpasser: einen Mouse-Listener und einen Key-Listener. Beide werden dem Panel zugeordnet. Der Mouse-Listener passt auf den Mauszeiger auf. Sobald dieser in das Panel eintritt, wird übergibt er den Fokus an das Panel, indem er die Methode requestfocus() des Panels aufruft. Verlässt der Mauszeiger das Panel, so übergibt der Listener den Fokus an die Text-Area. Um den Status des Panels optisch zu verdeutlichen, setzt der Listener die Hintergrundfarbe des Panel auf Rot, wenn es den Fokus hat und auf Orange, wenn es den Fokus nicht hat. Wir beschreiben zunächst die Implementierung des Panels. Die Klasse KeyPanel ist von JPanel abgeleitet. In der Definition der Klasse überschreiben wir die Methode isfocustraversable so, dass sie den Wert True zurück gibt. Damit kann ein KeyPanel den Fokus erhalten. Sonst wird gegenüber JPanel nichts geändert. 2
Datei: KeyPanel.java package eis.keytest; import javax.swing.jpanel; import java.awt.color; public class KeyPanel extends JPanel public boolean isfocustraversable()return true; KeyPanel() this.setbackground(color.orange); Die Klasse KeyFrame definiert den Rahmen, in den das Panel und die Text-Area eingeklebt werden. In ihr werden auch die beiden Listener als interne Klassen definiert. Durch die interne Definition können die Listenern auf einfache Weise auf die Subkomponenten und Variablen des Rahmens zugreifen. Wir beschreiben nur den Tastatur-Aufpasser genauer (Key-Listener, engl. key bedeutet Taste ). Dieser ist für das Verarbeiten von Tastenanschlägen zuständig. Das Interface KeyListener verlangt die Implementierung der folgenden Methoden. Jede erhält eine Ereignis vom Typ KeyEventKeyEvent übergeben, dem man Information über die gedrückte Taste entnehmen kann. public void keypressed(keyevent evt) public void keyreleased(keyevent evt) public void keytyped(keyevent evt) keypressed(keyevent evt) wird aufgerufen, wenn eine Taste gedrückt wird. keyreleased(keyevent evt) wird aufgerufen, wenn eine Taste (wirklich) losgelassen wird. keytyped(keyevent evt) wird aufgerufen, wenn eine Taste gedrückt und losgelassen wird. I.A. wird diese Methode vor keyreleased aufgerufen. 3
Das gerade beschriebene Verhalten ist in der Praxis allerdings oft etwas anders. Die meisten Betriebssysteme haben eine Wiederholfunktion, die bei länger gedrückter Taste eine rasche Folge von Anschlägen dieser Taste simuliert. Hält man eine Taste fest so ist die Reihenfolge der Aufrufe (auf einem Windows-System) keypressed - keytyped - keypressed - keytyped - keyreleased Das heißt, keyreleased wir erst beim physikalischen Loslassen der Taste ausgelöst. Dafür wird keytyped auch bei jedem vom Betriebssystem simulierten Anschlag ausgelöst. Um den Key-Listener keylis einer Swing-Komponente Komp zuzuordnen, benutzt man den Befehl Komp.addKeyListener(keyLis) Dem Objekt vom Typ KeyEvent kann man Informationen über die gedrückte Taste entnehmen. Die folgenden Methoden dienen diesem Zweck. char getkeychar(); int getkeychar(); static String getkeytext(int code); static String getkeymodifierstext(int code); getkeychar() liefert das Unicode-Zeichen, das die gedrückte Taste auf dem Bildschirm erscheinen lässt. getkeychar() den ganzzahligen Code, der der gedrückten Taste zugeordnet ist (Tastaturcode). static String getkeytext(int code) liefert eine textuelle Beschreibung, die zu dem Zeichen mit Tastaturcode code gehört. Dies ist bei Nicht- Buchstaben Tasten interessant, zum Beispiel bei der Umschalttaste, die Shift liefert. static String getkeymodifierstext(int code) liefert eine textuelle von Modifikator-Tasten wie Control. Man beachte, dass die beiden letztgenannten Methoden statisch sind. Die Kodierungen richten sich nach Rechnertyp und Betriebssystem. Im Folgenden sind die Listings der Programme KeyFrame und KeyTest angegeben. Das erste Programm definiert den Rahmen und die beiden Listener. Das zweite enthält die Startklasse. Zum Testen bewege man die Maus 4
in das obere Panel und drücke einige Tasten. Unten werden dann die Befehle des Listeners angezeigt angezeigt werden. Dabei muss das Fenster gewählt sein, das heißt die Titelleiste ist hervorgehoben. Ist der Mauszeiger nicht im Panel (und das Fenster gewählt), so hat die Text-Area den Fokus und man kann dort wie gewohnt Text eingeben. In Abbildung 1 ist das Resultat zu sehen. Datei: KeyFrame.java package eis.keytest; import javax.swing.*; import java.awt.*; import java.awt.event.*; import eis.simpleframe.simpleframe; public class KeyFrame extends SimpleFrame private private JTextArea keyprotocol; KeyPanel keypane; KeyFrame() keypane = new KeyPanel(); EisKeyListener eiskeylis = new EisKeyListener(); keypane.addkeylistener(eiskeylis); MausAdapter mdpt = new MausAdapter(); keypane.addmouselistener(mdpt); this.getcontentpane().add(keypane,"center"); this.setsize(600,400); this.setlocation(200,200); keyprotocol = new JTextArea(); keyprotocol.setfont(new Font("Monospaced",Font.PLAIN,12)); JScrollPane scrollpane = new JScrollPane(keyProtocol); scrollpane.setpreferredsize(new Dimension(600,150)); this.getcontentpane().add(scrollpane,"south"); 5
// Interne Klassen //Maus-Aufpasser public class MausAdapter extends MouseAdapter public void mouseentered(mouseevent e) keypane.requestfocus(); keypane.setbackground(color.red); public void mouseexited(mouseevent e) keypane.setbackground(color.orange); keyprotocol.requestfocus(); //interne Klasse //Tastatur-Aufpasser class EisKeyListener implements KeyListener public EisKeyListener() public void keytyped(keyevent evt) char c = evt.getkeychar(); int code = evt.getkeychar(); keyprotocol.append("getippt : Taste="+c+" Code="+code+"\n"); public void keypressed(keyevent evt) char c = evt.getkeychar(); int code = evt.getkeychar(); keyprotocol.append("gedrückt : Taste="+c+" Code="+code+"\n"); 6
public void keyreleased(keyevent evt) char c = evt.getkeychar(); int code = evt.getkeychar(); keyprotocol.append("losgelassen: Taste="+c+" //interne Klasse Code="+code+"\n"); Datei: KeyTest.java package eis.keytest; public class KeyTest public static void main(string[] args) KeyFrame keyfr = new KeyFrame(); keyfr.showit(); 7
Abbildung 1: Ergebins des Programms KeyTest. 8