Einfache Ereignisse und Interaktivität
von Laura Lemay
Java-Ereignisse sind Teil des Java-AWT-Pakets (Abstract Windowing Toolkit). Ein Ereignis ist die Art, wie AWT mit Ihnen als Programmierer und mit anderen AWT-Komponenten kommuniziert, wie wie etwas abläuft. Dieses etwas kann vom Benutzer eingegeben werden (Mausbewegungen oder Klicks, Drücken von Tasten) und ändert die Systemumgebung (ein Fenster wird geöffnet, geschlossen oder verschoben) oder andere Dinge, die in irgendeiner Weise für den Ablauf des Programms interessant sind.
Mit anderen Worten, wenn etwas mit einer AWT-Komponente, auch einem Applet, passiert, wird ein Ereignis erzeugt. Manche Ereignisse werden vom AWT oder vom Browser abgearbeitet, ohne daß Sie etwas tun müssen. Die paint()-Methoden werden beispielsweise vom Browser erzeugt und gehandhabt. Sie brauchen dem AWT nur mitzuteilen, was gezeichnet und wann und wo im Fenster ausgegeben werden soll. Andere Ereignisse, z. B. ein Mausklick innerhalb der Grenzen eines Applets, sind Ihnen nicht bekannt. Sie können aber Ihre Java-Programme so schreiben, daß diese Ereignisarten gehandhabt werden, um z. B. vom Benutzer Eingaben anzufordern und das Verhalten des Applets entsprechend diesen Eingaben zu ändern.
Heute lernen Sie die Handhabung einfacher Ereignisse, darunter:
Außerdem lernen Sie die Verwendung der handleEvent()-Methode, die die Grundlage für das Sammeln, Handhaben und Weitergeben von Ereignissen aller Art von Ihrem Applet zu anderen Komponenten im Fenster oder im Applet selbst bildet. Morgen lernen Sie, wie Ereignisse mit dem AWT kombiniert werden können, um für Ihr Applet eine komplette Benutzeroberfläche zu erstellen.
Wir beginnen mit dem häufigsten Ereignis: Mausklicks. Mausklickereignisse finden statt, wenn der Benutzer mit der Maus irgendwo in Ihrem Applet klickt. Sie können Mausklicks für einfache Dinge auslegen, z. B. zum Ein- und Ausschalten von Sound in einem Applet, zum Wechseln auf die nächste Folie einer Präsentation oder zum Leeren des Bildschirms. Sie können Mausklicks aber auch mit Mausbewegungen verbinden, so daß komplexere Aktionen in Ihrem Applet möglich sind.
Beim einmaligen Klicken der Maus erzeugt AWT zwei Ereignisse: mouseDown, wenn die Maustaste gedrückt wird, und mouseUp, wenn die Maustaste losgelassen wird. Warum zwei getrennte Ereignisse für eine Mausaktion? Weil für das Drücken eventuell andere Aktionen definiert werden sollen als für das Loslassen. Betrachten Sie beispielsweise ein Pulldown-Menü. Durch mouseDown wird das Menü geöffnet und mit mouseUp kann eine Option ausgewählt werden (dazwischen liegt mouseDrags, das lernen Sie aber später). Wenn Sie für beide Aktionen (mouseUp und mouseDown) nur ein Ereignis definieren, können Sie diese Art von Benutzerinteraktion nicht realisieren.
Die Handhabung von Mausereignissen in einem Applet ist einfach. Sie überschreiben lediglich die entsprechende Methodendefinition. Diese Methode wird aufgerufen, wenn das jeweilige Ereignis stattfindet. Hier ein Beispiel der Methodenunterschrift für ein mouseDown-Ereignis:
public boolean mouseDown(Event evt, int x, int y) { ... }
Die mouseDown()-Methode (und mouseUp()) erhalten drei Parameter: Das Ereignis und die x- und y-Koordinaten, wo das mouseDown- bw. mouseUp-Ereignis stattfindet.
Das Ereignisargument ist eine Instanz der Klasse Event. Alle Systemereignisse erzeugen eine Instanz der Event-Klasse, die Informationen darüber enthält, wo und wann das Ereignis stattfindet, um welches Ereignis es sich handelt und andere Informationen, die über ein Ereignis von Interesse sind. Zuweilen ist es nützlich, für das Ereignisobjekt eine Referenz zu erstellen, wie Sie später in dieser Lektion noch sehen werden.
Die x- und y-Koordinaten des Ereignisses werden von den x- und y-Argumenten weitergegeben und sind besonders nützlich, weil Sie auf ihrer Grundlage genau festlegen können, wo der Mausklick erfolgt.
Sie sehen hier eine einfache Methode, die Informationen über ein mouseDown-Ereignis zum Zeitpunkt der Ausführung ausgibt:
public boolean mouseDown(Event evt, int x, int y) { System.out.println("Mouse down at " + x + "," + y); return true; }
Durch Einbeziehen dieser Methode in Ihr Applet wird diese Meldung jedesmal, wenn der Benutzer mit der Maus in Ihrem Applet klickt, ausgegeben.
Im Gegensatz zu den anderen Systemmethoden, die wir bisher studiert haben, gibt diese Methode anstelle von void einen booleschen Wert aus. Die Bedeutung dieses Unterschieds wird morgen klar, wenn Sie Benutzeroberflächen erstellen und Eingaben für diese Oberflächen definieren. Mit einem Ereignis-Handler, der true oder false ausgibt, bestimmen Sie, ob eine bestimmte Komponente der Benutzeroberfläche in ein Ereignis eingreifen kann oder ob es an eine benachbarte Komponente abzugeben ist. Die allgemeine Regel lautet, daß Methoden, die mit Ereignissen zu tun haben, true ausgeben sollten, was zumindest in den Beispielen dieser Lektion immer der Fall ist.
Die zweite Hälfte des Mausklicks ist die mouseUp()-Methode, die aufgerufen wird, wenn die Maustaste gelöst wird. Zur Handhabung eines mouseUp-Ereignisses fügen Sie eine mouseUp()-Methode in Ihr Applet ein. mouseUp() sieht genauso aus wie mouseDown():
public boolean mouseUp(Event evt, int x, int y) { ... }
In diesem Abschnitt erstellen Sie ein Beispiel-Applet, das Mausereignisse, besonders mouseDown, nutzt. Das Spots-Applet beginnt mit einem leeren Bildschirm und bleibt dann ruhig abwartend. Wird die Maus in diesem Bildschirm geklickt, erscheint ein blauer Punkt. Sie können in diesem Bildschirm bis zu zehn Punkte anordnen. Abb. 12.1 zeigt das Spots-Applet.
Abbildung 12.1: Das Spots Applet
Wir erstellen dieses Applet nun von Anfang an. Beginnen Sie mit der Klassendefinition:
import java.awt.Graphics; import java.awt.Color; import java.awt.Event; public class Spots extends java.applet.Applet { final int maxspots = 10; int xspots[] = new int[maxspots];
int yspots[] = new int[maxspots];; int currspots = 0; }
In dieser Definition werden drei andere awt-Klassen verwendet: Graphics, Color und Event. Event muß in jedes Applet importiert werden, das Ereignisse nutzt. Die Klasse hat vier Instanzvariablen: Eine Konstante, um die Höchstzahl der zu zeichnenden Punkte festzulegen, zwei Arrays, um die x- und y-Koordinaten der bereits gezeichneten Punkte zu speichern, und eine Ganzzahl, um die Nummer des aktuellen Punkts zu verfolgen.
Jetzt schreiben Sie die init()-Methode, die aus einer Zeile besteht, um den Hintergrund auf Weiß zu setzen:
public void init() { setbackground(Color.white); }
Wir setzen den Hintergrund hier und nicht in paint(), weil paint() wiederholt jedesmal aufgerufen wird, wenn ein neuer Punkt hinzugefügt wird. Da Sie den Hintergrund nur einmal einstellen müssen, würde seine Einbeziehung in der paint()-Methode diese Methode unnötig verlangsamen.
Die Hauptaktion dieses Applets findet in der mouseDown()-Methode statt. Sie fügen jetzt eine solche Methode ein:
public boolean mouseDown(Event evt, int x, int y) { if (currspots < maxspots) addspot(x,y); else System.out.println("Too many spots."); return true; }
Findet der Mausklick statt, prüft die mousedown()-Methode, ob weniger als zehn Punkte vorhanden sind. Trifft das zu, ruft sie die addspot()-Methode auf (die ich gleich erkläre). Andernfalls wird eine Fehlermeldung ausgegeben. Schließlich gibt sie true aus, weil alle Ereignismethoden einen booleschen Wert (normalerweise true) ausgeben müssen.
Was bewirkt addspot()? Diese Methode fügt die Koordinaten des Punktes in die Arrays ein, in denen die Koordinaten gespeichert werden, erhöht die currspots-Variable und ruft dann repaint() auf:
void addspot(int x,int y) { xspots[currspots] = x; yspots[currspots] = y; currspots++; repaint(); }
Sie wundern sich vielleicht, warum man zusätzlich zum aktuellen Punkt auch alle bereits aktivierten Punkte verfolgen muß. Der Grund liegt an repaint(): Jedesmal, wenn der Bildschirm gezeichnet wird, müssen zusätzlich zum letzten auch alle alten Punkte ausgegeben werden. Andernfalls würde jeweils nur der neue Punkt erscheinen. Nun wenden wir uns der paint()-Methode zu:
public void paint(Graphics g) { g.setColor(Color.blue); for (int i = 0; i < currspots; i++) { g.fillOval(xspots[i] -10, yspots[i] -10,20,20); } }
Innerhalb von paint stellen Sie die in den xspots- und yspots-Arrays gespeicherten Punkte in eine Schleife, so daß einer nach dem anderen gezeichnet wird (leicht nach rechts oben gerückt, damit der Punkt rund um den Mauszeiger, nicht unterhalb rechts ausgegeben wird).
Das war's schon! Damit haben Sie ein Applet geschrieben, das Mausklicks bedient. Den Rest überlasse ich Ihnen. Sie müssen das entsprechende Verhalten für mouseDown() oder mouseUp() einfügen, damit die Ereignisse abgewickelt werden. Der volle Code für das Spots-Applet steht in Listing 12.1.
1: import java.awt.Graphics; 2: import java.awt.Color; 3: import java.awt.Event; 4: 5: public class Spots extends java.applet.Applet { 6: 7: final int maxspots = 10; 8: int xspots[] = new int[MAXSPOTS]; 9: int yspots[] = new int[MAXSPOTS]; 10: int currspots = 0; 11: 12: public void init() { 13: setBackground(Color.white); 14: } 15: 16: public boolean mouseDown(Event evt, int x, int y) { 17: if (currspots < MAXSPOTS) 18: addspot(x,y); 19: else System.out.println("Too many spots."); 20: return true; 21: } 22: 23: void addspot(int x, int y) { 24: xspots[currspots] = x; 25: yspots[currspots] = y; 26: currspots++; 27: repaint(); 28: } 29: 30: public void paint(Graphics g) { 31: g.setColor(Color.blue); 32: for (int i = 0; i < currspots; i++) { 33: g.fillOval(xspots[i] -10, yspots[i] -10,20,20); 34: } 35: } 36: }
Jedesmal, wenn die Maus um ein Pixel in eine Richtung bewegt wird, wird ein Mausbewegungsereignis erzeugt. Wir unterscheiden zwischen zwei Mausbewegungsereignissen: Ziehen der Maus, wobei die Bewegung bei gedrückter Maustaste stattfindet, und einfache Mausbewegungen, bei denen die Maustaste nicht gedrückt wird.
Für Mausbewegungsereignisse stehen die Methoden mouseDrag() und mouseMove() zur Verfügung.
Wenn Sie die mouseDrag()- und mouseMove()-Methoden in Ihren Applet-Code einbeziehen, werden Mausbewegungsereignisse gehandhabt. Die mouseMove()-Methode dient für einfache Mausbewegungen ohne Drücken der Maustaste. Eine einfache Methode dieser Art sieht so aus wie Mausklick-Methoden:
public boolean mouseMove(Event evt, int x, int y) { ... }
Die mouseDrag()-Methode bedient Mausbewegungen, bei denen die Maustaste gedrückt gehalten wird (eine komplette Ziehbewegung besteht aus einem mouseDown-Ereignis, einer Reihe von mouseDrag-Ereignissen für jedes Pixel, um die sich die Maus bewegt, und einem mouseUp-Ereignis, auch wenn die Maustaste nicht betätigt wird). Die mousedrag()-Methode sieht so aus:
public boolean mouseDrag(Event evt, int x, int y) { ... }
Ferner gibt es die mouseEnter()- und mouseExit()-Methoden. Diese zwei Methoden werden aufgerufen, wenn der Mauszeiger in das Applet eintritt bzw. es verläßt. (Falls Sie sich wundern, warum das für Sie von Interesse sein soll, kann ich Ihnen jetzt schon sagen, daß das für alle Komponenten der Benutzeroberfläche, die Sie in ein Applet einbeziehen, nützlich ist. Sie lernen hierüber morgen mehr.)
mouseEnter() und mouseExit() haben ähnliche Unterschriften und je drei Argumente: Das Ereignisobjekt und die x- und y-Koordinaten des Punkts, an dem die Maus in das Applet eintritt bzw. dieses verläßt.
public boolean mouseEnter(Event evt, int x, int y) { ... } public boolean mouseExit(Event evt, int x, int y) { ::: }
Ein praktisches Beispiel ist immer hilfreich, um Konzepte besser zu erklären. In diesem Abschnitt schreiben Sie ein Applet, mit dem gerade Linien am Bildschirm durch Ziehen der Maus vom Anfangs- zum Endpunkt erstellt werden. Das ausgeführte Applet sehen Sie in Abb. 12.2.
Abbildung 12.2: Linien zeichnen
Wie beim Spots-Applet (auf dem dieses Applet basiert), beginnen wir mit der Definition und arbeiten uns durch die einzelnen Schritte. Listing 12.2 enthält den Anfang des Lines-Applets.
1: import java.awt.Graphics; 2: import java.awt.Color; 3: import java.awt.Event; 4: import java.awt.Point; 5: 6: public class Lines extends java.applet.Applet { 7: 8: final int MAXLINES = 10; 9: Point starts[] = new Point[MAXLINES]; // Anfangspunkte 10: Point ends[] = new Point[MAXLINES]; // Endpunkte 11: Point anchor; // Anfang einer neuen Linie 12: Point currentpoint; // Ende der aktiven Linie 13: int currline = 0; // Anzahl der Linien 14: 15: public void init() { 16: setBackground(Color.white); 17: } 18:
Die drei wichtigen Ereignisse dieses Applets sind mouseDown(), um den Ankerpunkt für die aktuelle Linie zu setzen, mouseDrag(), um die aktuelle Linie während des Zeichnens zu animieren, und mouseUp(), um den Endpunkt für die neue Linie zu setzen. Da Sie für diese Werte Instanzvariablen haben, brauchen Sie nur die richtigen Variablen in die richtigen Methoden einzupflanzen. Hier sehen Sie mouseDown(), um den Ankerpunkt zu setzen:
public boolean mouseDown(Event evt, int x, int y) { anchor = new Point(x,y); return true; }
Während die Maus gezogen wird, um die Linie zu zeichnen, animiert das Applet die momentan gezeichnete Linie. Durch Ziehen der Maus bewegt sich die neue Linie vom Ankerpunkt zur Spitze des Mauszeigers. Das mouseDrag-Ereignis enthält den jeweils aktuellen Punkt, auf den sich die Maus bewegt, deshalb wird diese Methode benutzt, um den aktuellen Punkt zu verfolgen (und bei jeder Bewegung nachzuzeichnen, um die Linie zu »animieren«):
public boolean mouseDrag(Event evt, int x, int y) { currentpoint = new Point(x,y); repaint(); return true; }
Die neue Linie wird erst beim Loslassen der Maustaste in die Arrays der alten Linien eingefügt. Hier wird mit mouseUp() sichergestellt, daß die Höchstzahl der Linien nicht überschritten wurde, bevor die addline()-Methode (wird weiter unten beschrieben) aufgerufen wird:
public boolean mouseUp(Event evt, int x, int y) { if (currline < maxlines) addline(x,y); else System.out.println("Too many lines."); return true; }
In der addline()-Methode werden die Linien-Arrays aktualisiert und das Applet wird nachgezeichnet, um die jeweils neue Linie zu berücksichtigen:
void addline(int x, int y) { starts[currline] = anchor; ends[currline] = new Point(x,y); currline++; currentpoint = null; repaint(); }
Beachten Sie, daß in dieser Zeile auch currentpoint auf Null gesetzt wird. Warum? Weil der Prozeß der aktuellen Linie abgeschlossen ist. Indem Sie currentpoint auf Null setzen, können Sie diesen Wert in der paint()-Methode testen.
Die Ausgabe des Applets bedeutet, daß alle alten Linien, die in den starts- und ends-Arrays gespeichert sind, zusätzlich zur jeweils aktuellen Linie (deren Endpunkte in anchor bzw. currentpoint stehen) gezeichnet werden. Um die Animation der aktuellen Linie für den Benutzer gut sichtbar darzustellen, wird sie in Blau ausgegeben. Hier ist die paint()-Methode für das Lines-Applet:
public void paint(Graphics g) {
// Vorhandene Linien zeichnen for (int i = 0; i < currline; i++) { g.drawLine(starts[i].x, starts[i].y, ends[i].x, ends[i].y); } // Neue Linie zeichnen g.setColor(Color.blue); if (currentpoint != null) g.drawLine(anchor.x, anchor.y, currentpoint.x,currentpoint.y); }
Wenn Sie die jeweils aktuelle Linie in paint einbinden, können Sie vorab testen, ob currentpoint einen Wert von Null hat. In diesem Fall wird gerade keine Linie im Applet gezeichnet, deshalb besteht kein Grund, eine Linie auszugeben, die nicht existiert. Durch Testen von currentpoint (und indem currentpoint in der addline()-Methode auf Null gesetzt wird), können Sie die Ausgabe auf das beschränken, was nötig ist.
Mit nur 60 Codezeilen und ein paar grundlegenden Methoden haben Sie eine einfache Zeichnungsanwendung für den Web-Browser entwickelt. Listing 12.3 enthält den gesamten Code für das Lines-Applet, damit Sie die einzelnen bisher diskutierten Teile übersichtlich nachvollziehen können.
1: import java.awt.Graphics; 2: import java.awt.Color; 3: import java.awt.Event; 4: import java.awt.Point; 5: 6: public class Lines extends java.applet.Applet { 7: 8: final int MAXLINES = 10; 9: Point starts[] = new Point[MAXLINES]; // Anfangspunkte 10: Point ends[] = new Point[MAXLINES]; // Endpunkte 11: Point anchor; // Anfang einer neuen Linie 12: Point currentpoint; // Ende der aktiven Linie 13: int currline = 0; // Anzahl der Linien 14: 15: public void init() { 16: setBackground(Color.white); 17: } 18: 19: public boolean mouseDown(Event evt, int x, int y) { 20: anchor = new Point(x,y); 21: return true; 22: } 23: 24: public boolean mouseUp(Event evt, int x, int y) { 25: if (currline < MAXLINES) 26: addline(x,y); 27: else System.out.println("Too many lines."); 28: return true; 29: } 30: 31: public boolean mouseDrag(Event evt, int x, int y) { 32: currentpoint = new Point(x,y); 33: repaint(); 34: return true; 35: } 36: 37: void addline(int x,int y) { 38: starts[currline] = anchor; 39: ends[currline] = new Point(x,y); 40: currline++; 41: currentpoint = null; 42: repaint(); 43: } 44: 45: public void paint(Graphics g) { 46: 47: // Vorhandene Linien zeichnen 48: for (int i = 0; i < currline; i++) { 49: g.drawLine(starts[i].x, starts[i].y, 50: ends[i].x, ends[i].y); 51: } 52: 53: // Neue Linie zeichnen 54: g.setColor(Color.blue); 55: if (currentpoint != null) 56: g.drawLine(anchor.x, anchor.y, 57: currentpoint.x,currentpoint.y); 58: } 59: }
Jedesmal, wenn der Benutzer eine Taste auf der Tastatur drückt, wird ein Tastaturereignis erzeugt. Durch Verwendung von Tastaturereignissen können Sie die Werte der gedrückten Tasten erfassen, um eine Aktion auszuführen oder vom Benutzer Ihres Applets Eingaben anzufordern.
Um ein Tastaturereignis zu erfassen, verwenden Sie die keyDown()-Methode:
public boolean keyDown(Event evt, int key) { ... }
Die durch keyDown-Ereignisse erfaßten (und an keyDown() als key-Argument weitergegebenen) Tastenanschläge sind Ganzzahlen, die ASCII-Zeichenwerte darstellen. Dies beinhaltet alphanumerische Zeichen, Funktionstasten, Tabulatoren, Zeilenschaltungen usw. Um sie als Zeichen zu verwenden (z. B. für Ausgaben), müssen Sie sie in Zeichen umwandeln:
currentchar = (char)key;
Beim folgenden einfachen Beispiel einer keyDown()-Methode wird nur die gerade gedrückte Taste in der ASCII- und Zeichendarstellung ausgegeben:
public boolean keyDown(Event evt, int key) { System.out.println("ASCII value: " + key); System.out.println("Character: " + (char)key); return true; }
Die Event-Klasse bietet verschiedene Klassenvariablen, die sich auf mehrere nicht alphanumerische Standardtasten, z. B. die Pfeiltasten, beziehen. Werden diese Tasten in Ihrem Applet benutzt, können Sie den Code übersichtlicher gestalten, indem Sie in Ihrer keyDown()-Methode für diese Tasten Namen anstelle von numerischen Werten verwenden. Um beispielsweise zu testen, ob die PfeilAuf-Taste gedrückt wurde, können Sie folgenden Code schreiben:
if (key == Event.up) { ... }
Da diese Klassenvariablen ganzzahlige Werte enthalten, können Sie auch die switch-Anweisung verwenden, um sie zu testen.
In Tabelle 12.1 finden Sie Standardvariablen der Event-Klasse für verschiedene Tasten.
Klassenvariable | Taste |
Event.home Event.end Event.pgup Event.pgdn Event.up Event.down Event.left PfeilRechts |
Pos1 Ende BildAuf BildAb PfeilAuf Pfeilab PfeilLinks Event.right |
Tabelle 12.1: Standardtasten, die in der Event-Klasse definiert sind
Wir beschäftigen uns nun mit einem Applet, das Tastaturereignisse beinhaltet. Bei diesem Applet kann man ein Zeichen über die Tastatur eingeben, das dann in der Mitte des Applet-Fensters angezeigt wird. Dann kann das Zeichen mit den Pfeiltasten am Bildschirm verschoben werden. Durch Eingabe eines weiteren Zeichens ändert sich das momentan angezeigte Zeichen. Abb. 12.3 zeigt ein Beispiel.
Abbildung 12.3: Das Keys-Applet
Dieses Applet ist weniger komplex als das vorherige. Hier werden nur drei Methoden verwendet: init(), keyDown() und paint(). Auch die Instanzvariablen sind einfacher, weil lediglich die x- und y-Positionen des aktuellen Zeichens und die Werte dieses Zeichens verfolgt werden müssen. Der erste Teil dieser Klassendefinition sieht so aus:
import java.awt.Graphics; import java.awt.Event; import java.awt.Font; public class Keys extends java.applet.Applet { char currkey; int currx; int curry;
Die init()-Methode ist für drei Dinge zuständig: Setzen der Hintergrundfarbe, Setzen des Applet-Fonts (hier Helvetica Fett 36 Punkt) und Setzen der Anfangsposition für das Zeichen (Bildschirmmitte, abzüglich ein paar Punkte, damit das Zeichen leicht nach rechts oben versetzt wird):
public void init() { currx = (this.size().width / 2) -8; // Standard curry = (this.size().height / 2) -16; setBackground(Color.white); setFont(new Font("Helvetia", Font.bold,36)); }
Da das Verhalten des Applets auf Tastatureingaben basiert, findet die Hauptarbeit dieses Applets in der keyDown()-Methode statt:
public boolean keyDown(Event evt, int key) { switch (key) { case Event.down: curry += 5; break; case Event.up: curry -= 5; break; case Event.left: currx -= 5; break; case Event.right: currx += 5; break; default: currkey = (char)key; } repaint(); return true; }
Im Mittelpunkt der keyDown()-Methode befindet sich eine switch-Anweisung, die auf verschiedene Tastenereignisse testet. Ist das Ereignis eine Pfeiltaste, wird die Position des Zeichens entsprechend geändert. Ist das Ereignis eine andere Taste, ändert sich das Zeichen selbst. Die Methode endet mit repaint() und gibt true aus.
Die paint()-Methode ist hier fast inhaltslos. Es wird lediglich das aktuelle Zeichen an der aktuellen Position angezeigt. Beachten Sie, daß es beim anfänglichen Starten des Applets kein Anfangszeichen gibt und nichts zu zeichnen ist. Das muß berücksichtigt werden. Die currkey-Variable wird auf 0 initialisiert, so daß das Applet nur gezeichnet wird, wenn currkey einen tatsächlichen Wert hat:
public void paint(Graphics g) { if (currkey != 0) { g.drawString(String.valueOf(currkey), currx,curry); } }
1: import java.awt.Graphics; 2: import java.awt.Event; 3: import java.awt.Font; 4: 5: public class Keys extends java.applet.Applet { 6: 7: char currkey; 8: int currx; 9: int curry; 10: 11: public void init() { 12: currx = (this.size().width / 2) -8; // Standard 13: curry = (this.size().height / 2) -16; 14: 15: setBackground(Color.white); 16: setFont(new Font("Helvetica", Font.BOLD,36)); 17: } 18: 19: public boolean keyDown(Event evt, int key) { 20: switch (key) { 21: case Event.DOWN: 22: curry += 5; 23: break; 24: case Event.UP: 25: curry -= 5; 26: break; 27: case Event.LEFT: 28: currx -= 5; 29: break; 30: case Event.RIGHT: 31: currx += 5; 32: break; 33: default: 34: currkey = (char)key; 35: } 36: 37: repaint(); 38: return true; 39: } 40: 41: public void paint(Graphics g) { 42: if (currkey != 0) { 43: g.drawString(String.valueOf(currkey), currx,curry); 44: } 45: } 46: }
Zu den sogenannten Ergänzungstasten zählen Hochsteller (Shift), Steuertaste (Control) und Meta. Sie erzeugen selbst keine Tastenereignisse. Wenn Sie aber ein gewöhnliches Maus- oder Tastaturereignis erhalten, können Sie testen, ob eine dieser Tasten gedrückt wurde, während das Ereignis stattfand. In manchen Fällen ist das offensichtlich. Alphanumerische Tasten, die gleichzeitig mit dem Hochsteller gedrückt werden, erzeugen beispielsweise andere Zeichen als ohne. In anderen Fällen, insbesondere im Zusammenhang mit der Maus, soll ein Ereignis mit einer gedrückten Ergänzungstaste aktiviert werden, um es von der üblichen Version des jeweiligen Ereignisses zu unterscheiden.
Die Event-Klasse enthält drei Methoden, mit denen geprüft werden kann, ob eine Taste gleichzeitig mit einer Ergänzungstaste gedrückt wurde: shiftDown(), metaDown() und controlDown(). Alle drei geben boolesche Werte auf der Grundlage der Taste aus, mit der die Ergänzungstaste gedrückt wurde. Sie können diese drei Methoden in jeder beliebigen Ereignishandhabung (Maus oder Tastatur) verwenden, indem Sie sie zu dem Ereignis-Objekt, das an die jeweilige Methode weitergegeben wurde, aufrufen:
public boolean mouseDown(Event evt, int x, int y) { if (evt.shiftDown) // Hochsteller/Klick bewirken else // Üblichen Klick bewirken }
Die Standardmethoden zur Handhabung von Ereignissen in Applets, die Sie heute gelernt haben, werden eigentlich von einer globalen Methode namens handleEvent() aufgerufen. Die handleEvent()-Methode spiegelt die Art wider, in der AWT im allgemeinen mit Ereignissen umgeht, die zwischen Anwendungskomponenten und Ereignissen aufgrund von Benutzereingaben stattfinden.
In der Standardmethode handleEvent() werden Ereignisse verarbeitet und die Methoden, die Sie heute gelernt haben, werden aufgerufen. Um die hier beschriebenen Standardereignisse zu ändern oder eigene Ereignisse zu definieren und weiterzugeben, müssen Sie handleEvent in Ihrem Java-Programm überschreiben. Die handleEvent()-Methode sieht so aus:
public boolean handleEvent(Event evt) { ... }
Um spezifische Ereignisse zu testen, prüfen Sie die ID-Instanzvariable des Event-Objekts, das darin weitergegeben wird. Die Ereignis-ID ist eine Ganzzahl, jedoch definiert die Event-Klasse zum Glück eine ganze Reihe von Ereignis-IDs als Klassenvariablen, die Sie im Körper von handleEvent testen können. Da diese Klassenvariablen ganzzahlige Konstanten sind, eignet sich eine switch-Anweisung besonders gut. Die folgende handleEvent()-Methode ist ein einfaches Beispiel, bei dem Informationen über Mausereignisse ausgegeben werden:
public boolean handleEvent(Event evt) { switch (evt.id) { case Event.MOUSE_DOWN: System.out.println("MouseDown: " + evt.x + "," + evt.y); return true; case Event.MOUSE_UP: System.out.println("MouseUp: " + evt.x + "," + evt.y); return true; case Event.MOUSE_MOVE: System.out.println("MouseMove: " + evt.x + "," + evt.y); return true; case Event.MOUSE_DRAG: System.out.println("Mouse.Drag: " + evt.x + "," + evt.y); return true; default: return false; } }
Sie können auf folgende Tastaturereignisse testen:
Ferner können Sie auf folgende Mausereignisse testen:
Abgesehen von diesen Ereignissen enthält die Event-Klasse eine ganze Reihe von Methoden zur Handhabung von Komponenten der Benutzeroberfläche. Sie lernen diese Methoden morgen.
Wenn Sie handleEvent() in Ihrer Klasse überschreiben, wird keine der Standardereignismethoden, die Sie heute gelernt haben, automatisch aufgerufen. Sie müssen sie explizit im Körper von handleEvent() aufrufen. Deshalb müssen Sie beim Überschreiben sorgfältig vorgehen. Um Probleme zu vermeiden, können Sie auf ein Ereignis, an dem Sie interessiert sind, testen. Falls das gewünschte Ereignis dabei nicht aktiviert wird, rufen Sie super.handleEvent() auf, so daß die Superklasse, die handleEvent() definiert, die Aufgabe übernehmen kann. Nachfolgend ein Beispiel, wie das realisiert wird:
public boolean handleEvent(Event evt) { if (evt.id == Event.MOUSE_DOWN) { // Drücken der Maustaste verarbeiten return true; } else { return super.handleEvent(evt); } }
Die Handhabung von Javas AWT-Ereignissen (Abstract Windowing Toolkit) ist denkbar einfach. Größtenteils müssen Sie nur die richtige Methode auswählen, eventuell überschreiben (d. h. neu definieren) und in Ihren Applet-Code einfügen. Nachfolgend eine Übersicht über die grundlegenden Ereignisse, die Sie auf diese Weise anwenden können:
Alle AWT-Ereignisse erzeugen ein Event-Objekt. In diesem Objekt können Sie Informationen über das Ereignis finden, beispielsweise, wann es stattfindet, seine x- und y-Koordinaten usw. Ferner können Sie das Ereignis testen, um festzustellen, ob beim Eintritt des Ereignisses eine Ergänzungstaste gedrückt wurde. Hierfür wenden Sie die Methoden shiftdown(), controlDown() und metaDown() an.
Schließlich gibt es handleEvent(), die »Mutter« aller Ereignismethoden. Das Java-System ruft im Prinzip bei der Handhabung aller Ereignisse die handleEvent()-Methode auf. Soweit erforderlich, werden in der Standardimplementierung die einzelnen Methodenereignisse aufgerufen. Durch Überschreiben der Methoden Ihres Applets können Sie handleEvent individuell anpassen.
F: Im Spots-Applet sind die Punktkoordinaten in Arrays gespeichert, die eine begrenzte Größe haben. Wie kann ich dieses Applet abändern, so daß eine beliebige Zahl von Punkten gezeichnet werden kann?
A: Sie können das auf zwei Arten realisieren:
Erstens testen Sie Ihre addspot()-Methode, ob die Anzahl der Punkte MAXSPOTS überschreitet. Dann erstellen Sie ein größeres Array, kopieren die Elemente vom alten in dieses größere Array (benutzen Sie hierfür die Methode System.arraycopy()), und schließlich weisen Sie die x- und y-Arrays diesem neuen Array zu.
Zweitens können Sie die Vector-Klasse aus dem Paket java.util verwenden. Vector implementiert automatisch ein Array mit flexibler Größe, etwa wie eine verknüpfte Liste in anderen Sprachen. Vector hat den Nachteil, daß alles, was darin abgestellt wird, ein Objekt sein muß. Das bedeutet, daß Sie Ganzzahlen in Integer-Objekte umwandeln, deren Werte aus den Integer-Objekten herausziehen und sie wieder als Ganzzahlen behandeln müssen. Mit der Vector-Klasse können Sie Objekte am Ende von Vector ebenso hinzufügen oder entfernen wie in einem Array (indem Sie Methodenaufrufe anstelle der Array-Syntax verwenden). Probieren Sie das mal aus.
F: mouseDown() und mouseUp() scheinen nur auf eine Maustaste anwendbar zu sein. Wie kann ich bestimmen, welche Maustaste gedrückt wird?
A: In der derzeitigen Java-Version ist das nicht möglich. AWT unterstützt nur eine Maustaste. Bei Mäusen mit mehreren Tasten ist das standardmäßig die linke. Das schränkt die in einem Applet durchführbaren Aktionsmöglichkeiten zwar ein, sichert aber eine plattformunabhängige Lösung. Wie Sie wissen, hat jedes System eine andere Mausbedienung. Deshalb würden Sie beispielsweise durch Definieren der rechten Maustaste die Macintosh-Benutzer, deren Mäuse nur eine Taste haben, von Ihrem Applet ausschließen. Falls Sie unbedingt unterschiedliche Mausaktionen auf verschiedene Tasten legen wollen, realisieren Sie das mit Ergänzungstasten in den mouseDown()- und mouseUp()-Methoden.
F: Ich habe noch nie was von einer Meta-Taste gehört. Was ist damit gemeint?
A: Das ist eine Taste aus der Unix-Welt, die auf den meisten Tastaturen mit ALT bezeichnet ist. Da die Benutzer aller Plattformen wissen, was Hochsteller (Shift) und Steuertaste (Ctrl) sind, sollten Sie möglichst nur diese Ergänzungstasten verwenden.
F: Welchen Test kann ich verwenden, um festzustellen, ob die Return-Taste gedrückt wurde?
A: Ein Return (Zeilenvorschub) hat 10 Zeichen, während Enter (Zeilenschaltung) 13 Zeichen hat. Hier ist zu beachten, daß verschiedene Plattformen eventuell unterschiedliche Tasten für die mit Return gekennzeichnete Taste senden. Unix-Systeme senden beispielsweise Return-Zeichen, während der Macintosh Enter-Zeichen und DOS beides senden. Um plattformunabhängiges Verhalten sicherzustellen, müssen Sie sowohl auf Return als auch Enter testen.
Vom Java-Entwicklungsteam war zu erfahren, daß ungeachtet der Plattform ein Return ein Return ist. Bei Drucklegung war aber noch fraglich, ob das in der derzeitigen Version des Java Developer's Kit stimmt. Sie können das in der API-Dokumentation über die Event-Klasse nachlesen. Eventuell hat sich in der Zwischenzeit etwas geändert.
F: Ich habe in der API-Dokumentation die Event-Klasse nachgeschlagen und festgestellt, daß dort mehr Ereignisarten beschrieben werden als Sie heute erklärt haben.
A: Ja, das stimmt. Die Event-Klasse definiert viele verschiedene Ereignisarten für allgemeine Benutzereingaben, wie die Maus- und Tastaturereignisse, die Sie heute gelernt haben, und Ereignisse zur Handhabung von Zustandsänderungen von Komponenten der Benutzeroberfläche, z.B. Fenster und Bildlaufleisten. Diese Ereignisse lernen Sie morgen.
Copyright ©1996 Markt&Technik