In der Ereignisverarbeitung erfolgt ein Großteil der Aktionen Ihrer Anwendung. Bisher hat sich dieses Buch auf die grafische Schnittstelle zwischen Ihrer Anwendung und dem Anwender konzentriert. Jetzt wollen wir sehen, wie diese wunderbare Oberfläche zum Leben erweckt werden kann.
Java-Anwendungen reagieren durch Ereignsisse auf Nachrichten, die ihnen das System sendet. Wenn ein Anwender auf eine Schaltfläche klickt, ein Menüelement auswählt oder Text eingibt, wird dadurch eine Nachricht an Ihre Anwendung geschickt.
Das heutige Projekt heißt HandlingEvents.jpr, dem alle Listings hinzugefügt werden.
Wie Sie in den vergangenen Lektionen gesehen haben, ist es ganz einfach, Ereignis-Handler zu entwickeln. Sie wählne im Visual-Designer-Modus die Komponente im Designer oder im Menü-Designer, für den ein Ereignis verarbeitet werden soll - ein Menübefehl, eine Schaltfläche o.ä.
Um einen neuen Ereignis-Handler zu entwickeln, klicken Sie im Inspektor-Fenster auf die Registerkarte Ereignis und wählen dann das Ereignis aus, für das Sie eine Methode schreiben wollen. Klicken Sie einmal auf die rechte Spalten, um eine neue Methode anzugeben, und doppelklicken Sie dann, um den Fokus auf die Registerkarte Quelltext im AppBrowser zu verschieben. Der Cursor wird in dem Quellcode Ihrer neuen Methode zur Ereignisverarbeitung positioniert, und Sie können Ihre Befehle eingeben. Diese Prozedur haben Sie in Lektion 6 bereits kennengelernt. .
Wenn Sie einen existierenden Ereignis verwenden wollen, klicken Sie auf die Ereignis-Registerkarte und wählen ein Ereignis aus, für das Sie den existierenden Ereignis-Handler verwenden wollen. Klicken Sie auf die rechte Spalten und geben Sie den Namen der existierenden Methode ein. Das ist alles! Ihre Komponente oder Ihr Menüeintrag verwenden jetzt diese Methode für ihre eigenen Ereignisse.
Eine schnelle Methode, den Standard-Ereignis-Handler für eine Komponente zu erzeugen, ist, im Visual Designer auf die Komponente doppelzuklicken. Für die meisten Komponenten ist ein Standard-Ereignis definiert. Das Standard-Ereignis für eine Schaltfläche beispielsweise ist actionPerformed, und der Standard-Ereignis-Handler ist actionPerformed_buttonName. Das Ereignis actionPerformed ist auch der Standard für Komponenten, die keinen expliziten Standard definieren.
Wenn Sie einen Ereignis-Handler erzeugen, erzeugt die IDE neben dem Methoden-Rumpf automatisch den Code, der die Methode mit der Komponente verbindet. Unter anderem handelt es sich dabei um einen EventAdapter und einen EventListener, die als neue Klassen in Ihrem Quellcode erzeugt werden - diesen Code sollten Sie nicht verändern. Wie diese Klassen funktionieren, kann in diesem Buch nicht erklärt werden, aber sie stellen ein weiteres Beispiel dar, wie die IDE es vereinfacht, Java-Code zu schreiben. Immer wenn Sie Ihrem Projekt einen Frame hinzufügen, fügt die IDE außerdem automatisch die entsprechende Import-Zeile ein:
Damit können Ereignisse korrekt verarbeitet werden, wenn Sie Code für die Ereignisverarbeitung einfügen.
Um einen Ereignis-Handler zu löschen, wählen Sie seinen Namen in der rechten Spalte des Ereignisses und drücken die Entfernen-Taste. Dadurch wird der Ereignis-Handler von dem Ereignis gelöst, aber dadurch wird die Methode zur Ereignisverarbeitung noch nicht gelöscht. Das ist eine Sicherheitsfunktion, so daß eine Methode nicht einfach gelöscht werden kann, nur weil Sie gerade den letzten Verweis darauf gelöscht haben. (Vielleicht brauchen Sie sie später ja noch einmal.)
Um die Methode zur Ereignisverarbeitung ganz aus Ihrem Quellcode zu entfernen, entfenren Sie den Methoderumpf und lassen die leere Methodensignatur zurück. Beim nächsten Kompilieren wird der Code für diesen Handler (auch der automatisch erzeugte) aus Ihrer Quellcode-Datei entfernt.
Java-Ereignisse sind Teil des AWT-Pakets. Ein Ereignis stellt eine Möglichkeit dar, wie Komponenten mit Ihnen als Programmierer und mit anderen Komponenten kommunizieren. Dabei kann es um Eingaben vom Anwender (Mausklicks, Mausbewegungen, Tastencodes) Änderungen der Systemumgebung (ein Fenster hat sich geöffnet oder wurde geschlossen, das Fenster wurde gescrollt) oder zahllose andere Dinge handeln, die die Arbeitsweise des Programms auf irgendeine Weise beeinflußen.
Mit anderen Worten, wenn etwas in einer Komponente passiert, wird ein Ereignis erzeugt. Einige Ereignisse werden implizit verarbeitet, ohne daß Sie irgend etwas dazu tun müssen. Aufrufe der Methode paint() beispielsweise werden vom Browser erzeugt und verarbeitet - Sie müssen nur sagen, was gezeichnet werden soll. Einige Ereignisse jedoch, wie etwa ein Mausklick innerhalb Ihres Applets, müssen explizit verarbeitet werden, indem Code in einer Methode zur Ereignisverarbeitung geschrieben wird. Wenn Sie eigene Java-Programme schreiben, um diese Art von Ereignissen zu verarbeiten, können Sie Eingaben vom Anwender ermitteln und Ihr Programm kann basierend auf dieser Eingabe sein Verhalten ändern.
Mausereignisse gibt es in zwei grundlegenden Varianten, Mausklicks und Mausbewegungen.
Mausklick-Ereignisse treten auf, wenn ein Anwender eine der Maustasten drückt oder losläßt;
Mausbewegungs-Ereignisse treten
void this_mouseClicked(MouseEvent e) {...}
Alle Mausereignisse haben als Argument ein Objekt des Typs MouseEvent, dessen Konstruktormethonen-Header wie folgt aussieht:
public MouseEvent(Component source, int id, long when,
int modifiers, int x, int y,
int clickCount, boolean popupTrigger)
Der Parameter source ist das Objekt, das das Ereignis ausgelöst hat, etwa eine Schaltfläche oder ein Menüeintrag. Der Parameter id gibt an, welches Mausereignis stattgefunden hat (int-Konstanten: MOUSE_CLICKED, MOUSE_PRESSED, MOUSE_RELEASED, MOUSE_MOVED, MOUSE_ENTERED, MOUSE_EXITED oder MOUSE_DRAGGED). Jedes Ereignis hat einen eindeutigen Zeitstempel. Der Modifier-Parameter gibt an, ob eine der Modifier-Tasten gedrückt wurde (Shift, Alt oder Strg), als das Mausereignis stattfand. Die Parameter x und y gben die x,y-Koordinaten des Mausereignisses relativ zur Quellkomponente an. clickCount gibt an, wie viele Klicks stattgefunden haben. Ein Doppelklick beispielsweise würde einen clickCount von 2 erzeugen. Der Parameter popupTrigger ist true, wenn das Mausereignis ein Popup-Menü auf der Plattform verursacht hat, etwa ein Klick mit der rechten Maustaste in der Windows-Umgebung.
Dem MouseEvent-Objekt sind mehrere Methoden zugeordnet, die Ihnen Zugriff auf seine nicht-öffentlichen Instanzvariablen bieten:
Mit diesen Methoden ermitteln Sie Informationen über die MouseEvent-Instaznz in Ihren Methoden zur Verarbeitung des Mausereignisss. Weil der Standard-Ereignis-Handler, der vom JBuilder erzeugt wird, das MouseEvent als e bezeichnet, können Sie diese Methoden als e.getX() oder e.getClickCount() ansprechen. in your event handler
Mausklick-Ereignisse treten auf, wenn ein Anwender irgendwo auf Ihrem Applet oder in einem der Fenster Ihrer Anwendung eine Maustaste drückt. Sie können Mausklicks auffangen, um einfache Dinge auszuführen - den Sound im Applet ein- oder ausschalten, in einer Präsentation zum nächsten Bild weiterschalten oder den Bildschirm löschen und neu beginnen. Sie können die Mausklicks aber auch in Kombination mit Mausbewegungen betrachten, um komplexere Aktionen in Ihrem Programm auszuführen.
Wenn Sie mit der Maus klicken, werden mehrere Ereignisse erzeugt. Das mouseClicked-Ereignis zeigt, daß die Maus gedrückt und losgelassen wurde. Aber was ist, wenn Sie zwischen dem Drücken und dem Loslassen der Maustaste unterscheiden wollen? Betrachten Sie beispielsweise ein Pulldown-Menü. Wenn Sie die Maustaste drücken, wird das Menü aufgeklappt, wenn Sie sie loslassen, wird ein Menüeintrag ausgewählt. Wenn Sie nur ein Ereignis für beides hätten, könnten Sie eine solche Verwendung nicht implementieren. Neben dem mouseClicked-Ereignis erzeugt das Klicken mit der Maus also auch ein mousePressed-Ereignis.
Hier folgen drei einfache Button-Ereignis-Handler, die Koordinaten-Informationen ausgeben, wenn die Ereignisse mouseClicked, mousePressed oder mouseReleased auftreten:
void button1_mouseClicked(MouseEvent e) {
System.out.println("A mouseClicked event occurred at "
+ e.getX() + "," + e.getY());
}
void button1_mousePressed(MouseEvent e) {
System.out.println("A mousePressed event occurred at "
+ e.getX() + "," + e.getY());
}
void button1_mouseReleased(MouseEvent e) {
System.out.println("A mouseReleased event occurred at "
+ e.getX() + "," + e.getY());
}
Um den Handler zu erzeugen, selektieren Sie das Ereignis auf der Ereignis-Registerkarte. Klicken Sie auf die rechte Spalte, um den Handler anzugeben, und dann doppelklicken Sie, um den Methodenheader zu erzeugen (Sie können auch dreimal klicken, um diese beiden Schritte zusammenzufassen). Jetzt fügen Sie die beiden folgenden Codezeilen für die Methoden ein. Beachten Sie, daß die MouseEvent-Instanzvariablen nicht öffentlich sind un nur über die MouseEvent-Methoden zur Verfügung stehen.
Wenn Sie das ausprobieren, sehen Sie, daß für einen einfachen Mausklick drei Zeilen ausgegeben werden:
A mousePressed event occurred at 31,5
A mouseReleased event occurred at 31,5
A mouseClicked event occurred at 31,5
Das scheint ganz einfach zu sein: Die Maustaste wird gedrückt, wird freigegeben und der Mausklick ist abgeschlossen. Wenn Sie Klicken und Ziehen, bevor Sie loslassen, werden nur zwei Zeilen ausgegeben:
A mousePressed event occurred at 9,8
A mouseReleased event occurred at 42,10
Warum kein Mausklick? Das System weiß, daß etwas passiert ist (die Maus wurde gezogen), während die Maustaste gedrückt und losgelassen wurde, deshalb kann es die beiden nicht zu einem einfachen Mausklick auflösen und es wird kein mouseClicked-Ereignis erzeugt.
In diesem Abschnitt erzeugen Sie ein Applet, das das mousePressed-Ereignis verarbeitet. Es beginnt mit einem leeren Bildschirm und wartet. Wenn Sie auf den Bildschirm klicken, wird ein blauer Punkt gezeichnet.
Wir erzeugen das grundlegende Applet mit dem Applet-Experten. Bei geöffnetem Projekt HandlingEvents.jpg wählen Sie Datei | Neu und doppelklicken auf das Applet-Objekt. Wenn der erste Dialog des Applet-Experten erscheint, löschen Sie den Text im Package-Feld und geben in das Klasse-Feld Spots ein. Anschließend klicken Sie auf die Schaltfläche Fertigstellen. Dadurch wird ein Code-Gerüst für das Applet Spots.java erzeugt, ebenso wie die Datei Spots.html, mit der Sie Ihr Applet testen.
Klicken Sie im Struktur-Feld auf den Applet-Knoten (direkt unterhalb des Spots-Knotens), wodurch die Klassendeklaration von Spots markiert wird. Fügen Sie die folgenden Codezielen in den Inhalts-Bereich ein:
Dieser Code definiert die beiden Instanzvariablen der Klasse: die x- und y-Koordinaten, an der der aktuelle Punkt gezeichnet wird.
Jetzt wollen Sie die background-Eigenschaft für das Applet auf white setzen. Klicken Sie auf die Design-Registerkarte, um den AppBrowser in den Visual-Design-Modus zu versetzen. Das this-Objekt sollte selektiert werden; es stellt den Zeichenbereich Ihres Applets dar. Klicken Sie auf die Eigenschaften-Registerkarte des Inspektors, doppelklicken Sie auf die background-Eigenschaft und klicken Sie auf die Schaltfläche mit den drei Punkten, um den background-Dialog anzuzeigen. Klikken Sie auf den Dropdown-Pfeil im Auswahlfeld oben im Dialog und scrollen Sie nach oben, um White auszuwählen. Klicken Sie auf OK. Wenn Sie jetzt den Quellcode betrachten, sehen Sie, daß in der jbInit()-Methode eine neue Codezeile eingefügt wurde:
this.setBackground(Color.white);
Sie wollen hier die background-Eigenschaft setzen, und nicht in der paint()-Methode, weil paint() bei jedem neuen Hinzufügen eines Punkts aufgerufen wird. Weil Sie den Hintergrund nur einmal setzen müssen, würde das Setzen in der paint()-Methode das Ganze nur unnötig verlangsamen. Die hier gewählte Einstellung verbessert die Performance.
Die wichtigste Aktion dieses Applets erfolgt in der Methode mousePressed(). Um den Ereignis-Handler einzufügen, klicken Sie auf die Ereignis-Registerkarte des Inspektors. Jetzt klicken Sie dreimal in die rechte Spalte des Ereignisses mousePressed, um den Methodenheader in Ihrem Quellcode zu plazieren. Fügen Sie die foglenden Zeilen in seinen Rumpf ein:
x = e.getX();
y = e.getY();
repaint();
Wenn ein Mausklick erfolgt, setzt die Methode mousePressed() die Variablen x und y auf die von den Methoden getX() und getY() zurückgegebenen x- und y-Variablen. Anschließend wird die repaint()-Methode aufgerufen.
Sie müssen auch die update()-Methode überschreiben, um den internen Aufruf von repaint() zu eliminieren:
public void update(Graphics g) {
paint(g);
}
Dies ist keine Animation, warum also update() überschreiben? Wenn nicht, müßten Sie alle bereits vorhandenen Punkte und den aktuellen Punkt verwalten, so daß Sie sie neuzeichnen könnten, nachdem der interne Aufruf von repaint() in update() den Bildschirm Ihres Applets gelöscht hätte.
In Ihrer paint()-Methode könnten Sie in Reaktion auf Ihren Aufruf von repaint() im mousePressed-Ereignis die Punkte neu zeichnen:
public void paint(Graphics g) {
g.setColor(Color.blue);
g.fillOval(x - 10, y - 10, 20, 20);
}
Weil der Ursprung die obere linke Ecke des umschließenden Rechtecks ist, zeichnen Sie in dieser paint()-Methode den aktuellen Punkt ein bißchen weiter oben und links, so daß der Punkt um den Hotspot des Mauscursors gezeichnet wird, und nicht unterhalb und rechts davon. Listing 12.1 zeigt den Code für das Applet Spots.
1: import java.awt.*;
2: import java.awt.event.*;
3: import java.applet.*;
4: import borland.jbcl.layout.*;
5: import borland.jbcl.control.*;
6:
7: public class Spots extends Applet {
8: int x;
9: int y;
10: XYLayout xYLayout1 = new XYLayout();
11: boolean isStandalone = false;
12:
13: //Get a parameter value
14: public String getParameter(String key, String def) {
15: return isStandalone ? System.getProperty(key, def) :
16: (getParameter(key) != null ? getParameter(key) : def);
17: }
18:
19: //Construct the applet
20: public Spots() {
21: }
22:
23: //Initialize the applet
24: public void init() {
25: try { jbInit(); } catch (Exception e) { e.printStackTrace(); }
26: }
27:
28: //Component initialization
29: public void jbInit() throws Exception{
30: this.addMouseListener(new Spots_this_mouseAdapter(this));
31: this.setBackground(Color.white);
32: xYLayout1.setWidth(400);
33: xYLayout1.setHeight(300);
34: this.setLayout(xYLayout1);
35: }
36:
37: //Get Applet information
38: public String getAppletInfo() {
39: return "Applet Information";
40: }
41:
42: //Get parameter info
43: public String[][] getParameterInfo() {
44: return null;
45: }
46:
47: void this_mousePressed(MouseEvent e) {
48: x = e.getX();
49: y = e.getY();
50: repaint();
51: }
52:
53: public void update(Graphics g) {
54: paint(g);
55: }
56:
57: public void paint(Graphics g) {
58: g.setColor(Color.blue);
59: g.fillOval(x - 10, y - 10, 20, 20);
60: }
61: }
62:
63: class Spots_this_mouseAdapter extends java.awt.event.MouseAdapter {
64: Spots adaptee;
65:
66: Spots_this_mouseAdapter(Spots adaptee) {
67: this.adaptee = adaptee;
68: }
69:
70: public void mousePressed(MouseEvent e) {
71: adaptee.this_mousePressed(e);
72: }
73: }
Das ist alles, was Sie brauchen,um ein Applet zu erzeugen, das Mausklicks verarbeitet. Alles andere wird Ihnen abgenommen. Abbildung 12. 1 zeigt das Spots-Applet im appeltviewer, nachdem einige Punkte gezeichnet wurden.
Abbildung 12.1: Das Applet Spots
Um den Zeichenbereich zu löschen, minmieren Sie das appletviewer-Fenster und stellen es wieder her,um das Applet neu zu starten.
Immer wenn die Maus bewegt wird, werden Maus-Ereignisse erzeugt. Wie viele Ereignisse erzeugt werden, hängt von der Art der Mausbewegung ab:
Betrachten Sie die folgenden vier Ereignis-Handler, die auf diesen Ereignissen basieren:
void button1_mouseMoved(MouseEvent e) {
System.out.println("A mouseMoved event occurred at "
+ e.getX() + "," + e.getY());
}
void button1_mouseDragged(MouseEvent e) {
System.out.println("A mouseDragged event occurred at "
+ e.getX() + "," + e.getY());
}
void button1_mouseEntered(MouseEvent e) {
System.out.println("A mouseEntered event occurred at "
+ e.getX() + "," + e.getY());
}
void button1_mouseExited(MouseEvent e) {
System.out.println("A mouseExited event occurred at "
+ e.getX() + "," + e.getY());
}
Wenn Sie ein Applet mit diesen Ereignis-Handlern ausführen, sehen Sie, daß für eine Mausbewegung von fünf Pixeln fünf mouseMoved-Ereignisse erzeugt werden, eines für jedes Pixel, über das die Maus bewegt wird:
A mouseMoved event occurred at 31,5
A mouseMoved event occurred at 31,6
A mouseMoved event occurred at 31,7
A mouseMoved event occurred at 31,8
A mouseMoved event occurred at 31,9
A mousePressed event occurred at 48,7
A mouseDragged event occurred at 46,7
A mouseDragged event occurred at 45,8
A mouseDragged event occurred at 44,8
A mouseDragged event occurred at 43,8
A mouseDragged event occurred at 42,8
A mouseReleased event occurred at 42,8
A mouseEntered event occurred at 112,78
A mouseMoved event occurred at 16,0
A mouseMoved event occurred at 16,1
A mouseMoved event occurred at 16,2
A mouseMoved event occurred at 16,2
A mouseMoved event occurred at 16,3
A mouseMoved event occurred at 16,4
A mouseMoved event occurred at 16,5
A mouseMoved event occurred at 16,6
A mouseMoved event occurred at 16,7
A mouseMoved event occurred at 16,8
A mouseMoved event occurred at 16,9
A mouseMoved event occurred at 16,10
A mouseMoved event occurred at 16,11
A mouseMoved event occurred at 16,12
A mouseMoved event occurred at 16,13
A mouseMoved event occurred at 16,14
A mouseMoved event occurred at 16,15
A mouseMoved event occurred at 16,16
A mouseMoved event occurred at 16,17
A mouseMoved event occurred at 16,18
A mouseMoved event occurred at 16,19
A mouseMoved event occurred at 16,20
A mouseMoved event occurred at 16,21
A mouseMoved event occurred at 16,22
A mouseExited event occurred at 16,23
Alle bisher gezeigten Beispiele sezten voraus, daß Sie die Maus langsam und gleichmäßig passieren. Was passiert, wenn Sie sie schnell über eine Komponente schieben? Kann das System wirklich jedes Pixel erkennen? Hier die Ausgabe, die entsteht, wenn die Komponente button1 schnell überquert wird:
A mouseEntered event occurred at 133,89
A mouseMoved event occurred at 38,11
A mouseExited event occurred at 38,29
Beispiele verdeutlichen vieles. In diesem Abschnitt entwickeln Sie ein Applet, mit dem Sie 10 gerade Linien auf dem Bildschirm zeichnen können, indem Sie die Maus von einem Anfangspunkt zu einem Endpunkt verschieben. Abbildung 12.2 zeigt das Applet Lines.
Abbildung 12.2: Das Applet Lines
Wählen Sie bei geöffnetem HandlingEvents.jpr -Projekt in der IDE Datei | Neu und doppelklicken Sie auf das Applet-Objekt. Wenn der erste Schritt des Applet-Experten erscheint, löschen Sie den Text im Packages-Feld und geben in das Klasse-Feld Lines ein. Klicken Sie auf die Schaltfläche Fertigstellen. Jetzt wird das Code-Gerüst für das Applet Lines.java erzeugt, ebenso wie die HTML-Datei Lines.html.
Klicken Sie im Struktur-Feld auf de Applet-Knoten (unterhalb von Lines), so daß die Klassendeklaration hervorgehoben dargestellt wird. Fügen Sie die folgenden Codezeilen unterhalb dieser Zeile im Inhalts-Bereich ein:
int MAXLINES = 10;
Point starts[] = new Point[MAXLINES]; // Startpunkte
Point ends[] = new Point[MAXLINES]; // Endpunkte
Point anchor = null; // Anfang aktuelle Linie
Point currPoint = null; // Ende aktuelle Linie
int currLine = 0; // Anzahl Linien
Dieser Code definiert die Instanzvariablen der Klasse Lines:
Jetzt klicken Sie auf die Design-Registerkarte des AppBrowsers, klicken auf die Eigenschaften-Seite des Inspektors und setzen die background-Eigenschaft auf pink, so daß die folgende Codezeile in der jbInit()-Methode erzeugt wird:
this.setBackground(Color.pink);
Die drei wichtigsten Ereignisse in diesem Applet sind mousePressed, das den Ankerpunkt für die aktuelle Linie setzt, mouseDragged, das die aktuelle Linie zeichnet, und mouseReleased, das den Endpunkt für die neue Linie setzt. Mit den eben erzeugten Instanzvariablen ist es nur noch erforderlich, die richtigen Variablen in die richtigen Methoden einzugeben, und zu prüfen, ob MAXLINES bereits überschritten ist.
Klicken Sie auf die Design-Registerkarte, dann auf die Ereignisse-Registerkarte des Inspektors, und klicken Sie dreimal auf die rechte Spalte von mousePressed, um den Methodenheader in Ihren Quellcode einzufügen. Schreiben Sie die folgenden Zeilen in den Rumpf:
if (currLine <= MAXLINES)
anchor = new Point(e.getX(), e.getY());
Wenn der Mausklick auftritt, setzt mousePressed() das Point-Objekt anchor auf die x- und y-Variablen, die von getX() und getY() zurückgegeben wurden.
Jetzt wollen Sie einen Gummiband-Effekt realisieren, so daß die Linie beim Zeichnen der Maus folgt.
Klicken Sie auf die Design-Registerkarte, um in de Design-Modus zu wechseln, klicken Sie dreimal auf das Ereignis mouseDragged und fügen Sie den folgenden Code in die Methode ein:
if (currLine <= MAXLINES) {
currPoint = new Point(e.getX(), e.getY());
repaint();
}
Das mouseDragged-Ereignis enthält den aktuellen Punkt, wenn die Maus gezogen wird, deshalb verwenden Sie diesen Ereignis-Handler, um den aktuellen Punkt zu verfolgen und ihn für jede Bewegung neu zu zeichnen, so daß die Linie animiert erscheint.
Anfangs- und Endpunkt der neuen Linie werden erst in die Arrays eingetragen, wenn die Maustaste losgelassen wird. Das erfolgt in der Methode addLine(). Klicken Sie auf die Design-Registerkarte, klicken Sie dreimal auf mouseReleased und fügen Sie den folgenden Code ein:
if (currLine <= MAXLINES)
addLine(e.getX(), e.getY());
Wenn Sie die maximale Anzahl Zeien erreicht haben, sehen Sie die weiße Linie, wenn Sie zeichnen, aber sie wird der aktuellen Liste der Linien nicht mehr hinzugefügt. Hier die addLine()-Methode, die Sie nach der mouseReleased()-Methode einfügen können:
void addLine(int x, int y) {
starts[currLine] = anchor;
ends[currLine] = new Point(x, y);
currLine++;
currPoint = null;
repaint();
}
Beim Zeichnen des Applets werden alle alten Linien gezeichnet, deren Endpunkte und Anfangspunkte in den Arrays starts und ends gespeichert sind, ebenso wie der aktuellen Linie, deren Anfangs- und Endpunkte in anchor und currPoint abgelegt sind. Um die Animation der aktuellen Linie anzuzeigen, zeichnen Sie sie weiß. Hier die paint()-Methode (fügen Sie diesen Code unterhalb der Methode addLine() ein):
public void paint(Graphics g) {
// draw existing lines
for (int i = 0; i < currLine; i++) {
g.drawLine(starts[i].x, starts[i].y, ends[i].x, ends[i].y);
}
// draw current line
g.setColor(Color.white);
if ((currLine <= MAXLINES) & (currPoint != null))
g.drawLine(anchor.x, anchor.y, currPoint.x, currPoint.y);
}
In der paint()-Methode wird beim Zeichnen der aktuellen Linie neben der Überprüfung von MAXLINES geprüft, ob currPoint gleich null ist. Wenn das der Fall ist, zeichnet das Applet gerade keine Linie und es gibt keinen Grund, es neu zu zeichnen. Durch einen Test auf currPoint können Sie genau das zeichnen, was Sie brauchen. Durch Einfügen einiger weniger Codezeilen in den Ereignis-Handlern und einiger grundlegender Methoden haben Sie damit ein erstes Zeichen-Applet. Listing 12.2 zeigt den Code für das Applet Lines.
1: import java.awt.*;
2: import java.awt.event.*;
3: import java.applet.*;
4: import borland.jbcl.layout.*;
5: import borland.jbcl.control.*;
6:
7: public class Lines extends Applet {
8: int MAXLINES = 10;
9: Point starts[] = new Point[MAXLINES]; // startpoints
10: Point ends[] = new Point[MAXLINES]; // endpoints
11: Point anchor = null; // start of current line
12: Point currPoint = null; // current end of line
13: int currLine = 0; // number of lines
14: XYLayout xYLayout1 = new XYLayout();
15: boolean isStandalone = false;
16:
17: //Construct the applet
18: public Lines() {
19: }
20:
21: //Initialize the applet
22: public void init() {
23: try { jbInit(); } catch (Exception e) { e.printStackTrace(); }
24: }
25:
26: //Component initialization
27: public void jbInit() throws Exception{
28: this.addMouseListener(new Lines_this_mouseAdapter(this));
29: this.addMouseMotionListener(new Lines_this_mouseMotionAdapter(this));
30: this.setBackground(Color.pink);
31: xYLayout1.setWidth(400);
32: xYLayout1.setHeight(300);
33: this.setLayout(xYLayout1);
34: }
35:
36: //Get Applet information
37: public String getAppletInfo() {
38: return "Applet Information";
39: }
40:
41: //Get parameter info
42: public String[][] getParameterInfo() {
43: return null;
44: }
45:
46: void this_mousePressed(MouseEvent e) {
47: if (currLine <= MAXLINES)
48: anchor = new Point(e.getX(), e.getY());
49: }
50:
51: void this_mouseDragged(MouseEvent e) {
52: if (currLine <= MAXLINES) {
53: currPoint = new Point(e.getX(), e.getY());
54: repaint();
55: }
56: }
57:
58: void this_mouseReleased(MouseEvent e) {
59: if (currLine <= MAXLINES)
60: addLine(e.getX(), e.getY());
61: }
62:
63: void addLine(int x, int y) {
64: starts[currLine] = anchor;
65: ends[currLine] = new Point(x, y);
66: currLine++;
67: currPoint = null;
68: repaint();
69: }
70:
71: public void paint(Graphics g) {
72:
73: // draw existing lines
74: for (int i = 0; i < currLine; i++) {
75: g.drawLine(starts[i].x, starts[i].y, ends[i].x, ends[i].y);
76: }
77:
78: // draw current line
79: g.setColor(Color.white);
80: if ((currLine <= MAXLINES) & (currPoint != null))
81: g.drawLine(anchor.x, anchor.y, currPoint.x, currPoint.y);
82: }
83: }
84:
85: class Lines_this_mouseAdapter extends java.awt.event.MouseAdapter {
86: Lines adaptee;
87:
88: Lines_this_mouseAdapter(Lines adaptee) {
89: this.adaptee = adaptee;
90: }
91:
92: public void mousePressed(MouseEvent e) {
93: adaptee.this_mousePressed(e);
94: }
95:
96: public void mouseReleased(MouseEvent e) {
97: adaptee.this_mouseReleased(e);
98: }
99: }
100:
101: class Lines_this_mouseMotionAdapter
[ccc]extends java.awt.event.MouseMotionAdapter {
102: Lines adaptee;
103:
104: Lines_this_mouseMotionAdapter(Lines adaptee) {
105: this.adaptee = adaptee;
106: }
107:
108: public void mouseDragged(MouseEvent e) {
109: adaptee.this_mouseDragged(e);
110: }
111: }
In der Elternklasse von MouseEvent, InputEvent, sind drei modifier-Variablen definiert, die sich insbesondere auf Mausereignisse beziehen. Es handelt sich dabei um BUTTON1_MASK, BUTTON2_MASK und BUTTON3_MASK. Weil diese Konstanten als int-Werte gespeichert sind, können Sie sie in einer switch-Anweisung vewrenden, nachdem Sie den Wert durch Aufruf von getModifiers() ermittelt haben, die auch von InputEvent geerbt wurde.
switch (e.getModifiers()) {
case BUTTON1_MASK:
// linke Taste
break;
case BUTTON2_MASK:
// mittlere Taste
break;
case BUTTON3_MASK:
// rechte Taste
break;
}
Wenn Sie das Drücken der Tasten nicht explizit verarbeiten, wird die linke Maustaste vorausgesetzt. Neben diesen mausbezogenen Konstanten gibt es noch vier weitere Konstanten: ALT_MASK, CTRL_MASK, META_MASK und SHIFT_MASK. Um auf diese Modifier-Tasten zu prüfen, verwenden Sie die Booleschen Methoden isAltDown(), isCtrlDown(), isMetaDown() und isShiftDown() (ebenfalls in InputEvent definiert). Die letzten vier Modifierkönnen auch für Tastatur-Ereignisse verwendet werden.
Tastaturereignisse werden erzeugt, wenn der Anwender eine Taste oder eine Tastenkombination drückt. Mit Hilfe der Tastaturereignisse können Sie die Werte der gedrückten Tasten ermitteln, um eine entsprechende Aktion vorzunehmen, oder einfach Zeicheneingaben von den Anwendern Ihres Programms entgegenzunehmen.
Die Verarbeitung von Tastaturereignissen ist so einfach wie die Verarbeitung von Mausereignissen. Sie müssen einfach nur die entsprechenden Ereignis-Handler erzeugen. Der Methodenheader, der in Ihren Quellcode eingefügt wird, könnte wie folgt aussehen:
void textField1_keyPressed(KeyEvent e) {...}
Alle Tastaturereignisse haben als Argument ein Objekt vom Typ KeyEvent, dessen Konstruktormethodenheader so aussehen könnte:
public KeyEvent(Component source, int id, long when,
int modifiers, int keyCode, char keyChar)
Der Parameter source ist das Objekt, das das Ereignis ausgelöst hat, etwa ein TextField oder ein TextArea. Der Parameter id gibt an, welche Art Ereignis aufgetreten ist (int-Kosntanten: KEY_PRESSED, KEY_RELEASED oder KEY_TYPED). Jedes Ereignis hat einen eindeutigen when-Zeitstempel. Der modifiers-Parameter gibt an, ob eine oder mehrere Modifier-Tasten (Shift, Alt oder Strg) gedrückt waren, als das Tastaturereignis stattgefunden hat. Der keyCode ist der ASCII-Wert der Taste, keyChar ist das Unicode-Zeichen für die Taste.
Die Klasse KeyEvent definiert Methoden, die Ihnen Zugriff auf ihre nicht-öffentlichen Instanzvariablen gibt:
Diese Methoden können in Ihren Methoden zur Ereignisverarbeitung verwendet werden, um die instantiierten Variablen zu verwnden, wenn ein KeyEvent auftritt. Wie das MouseEvent benennt JBuilder das KeyEvent standardmäßig ebenfalls mit dem Bezeichner e, sie können also in Ihrem Ereignis-Handler als e.getKexCode() oder e.getKeyChar()auf diese Methoden zugreifen.
Wie Sie aus diesen Methodenüberblicken sehen, ist die keyCode-Variable als Integer definiert. Weil dieser Wert als Integer abgelegt wird, kann er in einer switch-Anweisung verwwendet werden, so wie die bereits beschriebenen modifier. Tabelle 12.1 bietet einen kurzen Überblick über die häufigsten keyCode-Konstanten.
Tabelle 12.1: keyCode-Konstanten
[Wird zurückgegeben, wenn es kein entsprechendes Unicode-Zeichen gibt] |
||
VK_NUM_LOCK |
||
Eine vollständige Liste finden Sie in den Java-Hilfedateien unter dem Thema java.awt.event.KeyEvent
Es gibt drei Ereignisse, um Tastendrücke aufzufangen, die denen für Mausklicks entsprechen: keyPressed, keyReleased und keyTyped. Hier folgen drei einfache TextArea-Ereignis-Handler, die das Ereignis und keyText für jedes Ereignis ausgeben, wozu die Methoden getKeyCode() und getKeyText() verwendet werden.
void textArea1_keyPressed(KeyEvent e) {
System.out.println("A keyPressed event occurred.");
System.out.println("Keyboard Key: " + e.getKeyText(e.getKeyCode()));
}
void textArea1_keyReleased(KeyEvent e) {
System.out.println("A keyReleased event occurred.");
System.out.println("Keyboard Key: " + e.getKeyText(e.getKeyCode()));
}
void textArea1_keyTyped(KeyEvent e) {
System.out.println("A keyTyped event occurred.");
System.out.println("Keyboard Key: " + e.getKeyText(e.getKeyCode()));
}
Wenn Sie das ausprobieren, sehen Sie, daß bei jedem drücken einer Zeichen-Taste alle drei Ereignisse erzeugt werden: zuerst ein keyPressed-Ereignis, gefolgt von einem keyTyped-Ereignis und einem keyReleased-Ereignis.
A keyPressed event occurred.
Keyboard Key: A
A keyTyped event occurred.
Keyboard Key: Unknown keyCode: 0x0
A keyReleased event occurred.
Keyboard Key: A
Wenn das Drücken einer Taste immer ein keyPressed- und ein keyReleased-Ereignis erzeugt, warum werden dann zwei separate Ereignisse verwendet? Das wird so genhandhabt, damit Sie die Reihenfolge der Tasten in Tastenkombinationen ermitteln können. Angenommen, Sie wollen einen Textblock in einem Texteditor-Applet einrücken, indem Sie die Tastenkombination Strg+B+I drücken. Ihr Applet fordert jedoch, daß di Strg-Taste gedrückt bleibt, während B und I gedrückt werden, weil Strg+B eine andere Aktion bewirken würde. Angenommen, im Applet ist ein Textblock selektiert, dann würde das wie folgt ablaufen:
Wenn diese sechs Ereignisse nicht in dieser Reihenfolge auftreten, wird nichts ausgeführt. Und das passiert, wenn Sie die folgende Tastensequenz in ein Programm mit unseren Testmethoden eingeben:
A keyPressed event occurred.
Keyboard Key: Up
A keyReleased event occurred.
Keyboard Key: Up
A keyPressed event occurred.
Keyboard Key: Down
A keyReleased event occurred.
Keyboard Key: Down
A keyPressed event occurred.
Keyboard Key: Enter
A keyTyped event occurred.
Keyboard Key: Unknown keyCode: 0x0
A keyReleased event occurred.
Keyboard Key: Enter
Dieser Abschnitt betrachtet ein Applet, das Tastaturereignisse verarbeitet. Es ermöglicht Ihnen, ein Zeichen einzugeben, und zeigt dieses Zeichen in der Mitte des Applet-Fensters an. Sie können dieses Zeichen mit Hilfe der Pfeiltasten auch auf dem Bildschirm verschieben. Die Eingabe eines neuen Zeichens starten Sie den Vorgang von Neuem.
Dieses Applet ist weniger kompliziert als die zuvor entwickelten Ereignisse, weil nur ein keyPressed-Ereignis-Handler, eine paint()-Methode, zwei Additionen in der init()-Methode und zwei Eigenschaftseinstellungen erforderlich sind.
Wählen Sie bei geöffnetem Projekt HandlingEvents.jpr in der IDE Datei | Neu und doppelklicken Sie auf das Applet-Objekt. Im ersten Schritt des Applet-Experten löschen Sie den Text im Package-Feld und geben in das Klasse-Feld KeyTest ein. Dadurch erzeugen Sie das Gerüst für das Applet KeyTest.java sowie ine KeyTest.html-Datei. Fügen Sie die folgenden Zeilen in die KeyTest-Klassendeklaration ein:
char currKey = 'A';
int currX;
int currY;
Dieser Code definiert die Instanzvariablen der Klasse KeyTest: currKey verfolgt, wenn sich das Zeichen ändert (initialisiert mit A), und currX und currY geben die x,y-Koordinaten des Zeichens an.
Jetzt klicken Sie auf die Design-Registerkarte im AppBrowser, dann auf die Eigenschaften-Registerkarte im Inspektor und setzen die background-Eigenschaft auf Green. Doppelklicken Sie auf die font-Eigenschaft und dann auf die Schaltfläche mit den drei Punkten, um den font-Dialog anzuzeigen. Wählen Sie Helvetica, Fett und 36 und klicken Sie auf OK. Diese Eigenschafts-Einstellungen erzeugen die folgenden beiden Codezeilen in der Methode jbInit():
this.setFont(new Font("Helvetica", 1, 36));
this.setBackground(Color.green);
Jetzt müssen Sie die nächste Codezeile an das Ende der jbInit()-Methode eingeben, so daß Ihr Applet die Tastencodes auffängt:
Klicken Sie auf die Quelltext-Registerkarte, um in den Projekt-Browser-Modus zu gehen, und setzen Sie die Anfangsposition für das Zeichen (etwa in der Mitte des Bildschirms), indem Sie am Ende der init()-Methode die folgenden Zeilen ein:
currX = (getSize().width / 2);
currY = (getSize().height / 2);
Weil das Verhalten dieses Applets auf der Tastatureingabe basiert, erfolgt ein Großteil der Arbeit im keyPressed-Ereignis-Handler. Klicken Sie auf die Design-Registerkarte und klicken Sie dreimal auf das keyPressed-Ereignis, um den Methodenheader einzufügen und die folgenden Codezeilen einzutragen:
switch (e.getKeyCode()) {
case e.VK_UP:
currY -= 5;
break;
case e.VK_DOWN:
currY += 5;
break;
case e.VK_LEFT:
currX -= 5;
break;
case e.VK_RIGHT:
currX += 5;
break;
default:
currKey = e.getKeyChar();
}
repaint();
Dadurch wird die Zeichenposition bei jedem Drücken einer Pfeiltaste um fünf Pixel verschoben und das Zeichen wird geändert, wenn eine andere Taste gedrückt wird. Tasten, die keine Zeichen und keine Pfeilrichtungen darstellen, werden ignoriert. Jetzt erzeugen wir noch die paint()-Methode, die ganz einfach ist:
public void paint(Graphics g) {
g.drawString(String.valueOf(currKey), currX, currY);
}
Sie gibt einfach das aktuelle Zeichen an der aktuellen Position aus. Listing 12.3 zeigt den Code für KeyTest.
1: import java.awt.*;
2: import java.awt.event.*;
3: import java.applet.*;
4: import borland.jbcl.layout.*;
5: import borland.jbcl.control.*;
6:
7: public class KeyTest extends Applet {
8: char currKey = 'A';
9: int currX;
10: int currY;
11: XYLayout xYLayout1 = new XYLayout();
12: boolean isStandalone = false;
13:
14: //Applet erzeugen
15: public KeyTest() {
16: }
17:
18: //Applet initialisieren
19: public void init() {
20: try { jbInit(); } catch (Exception e) { e.printStackTrace(); }
21: currX = (getSize().width / 2);
22: currY = (getSize().height / 2);
23: }
24:
25: // Komponenten initialisieren
26: public void jbInit() throws Exception{
27: this.addKeyListener(new KeyTest_this_keyAdapter(this));
28: this.setFont(new Font("Helvetica", 1, 36));
29: this.setBackground(Color.green);
30: xYLayout1.setWidth(400);
31: xYLayout1.setHeight(300);
32: this.setLayout(xYLayout1);
33: this.requestFocus();
34: }
35:
36: public String getAppletInfo() {
37: return "Applet Information";
38: }
39:
40: // Parameter-Information ermitteln
41: public String[][] getParameterInfo() {
42: return null;
43: }
44:
45: void this_keyPressed(KeyEvent e) {
46: switch (e.getKeyCode()) {
47: case e.VK_UP:
48: currY -= 5;
49: break;
50: case e.VK_DOWN:
51: currY += 5;
52: break;
53: case e.VK_LEFT:
54: currX -= 5;
55: break;
56: case e.VK_RIGHT:
57: currX += 5;
58: break;
59: default:
60: currKey = e.getKeyChar();
61: }
62: repaint();
63: }
64:
65: public void paint(Graphics g) {
66: g.drawString(String.valueOf(currKey), currX, currY);
67: }
68: }
69:
70: class KeyTest_this_keyAdapter extends java.awt.event.KeyAdapter {
71: KeyTest adaptee;
72:
73: KeyTest_this_keyAdapter(KeyTest adaptee) {
74: this.adaptee = adaptee;
75: }
76:
77: public void keyPressed(KeyEvent e) {
78: adaptee.this_keyPressed(e);
79: }
80: }
Neben Tastatur- und Mausereignissen bietet der AWT mehrere Standardereignisse, auf die Sie auf Ihrer Oberfläche reagieren können. Die meisten der Ereignis-Handler für diese Ereignisse können über die Ereignisse-Registerkarte des Inspektors gesetzt werden, so wie schon für Maus- und Tastaturereignisse. Abbildung 12.3 zeigt einen Teil der Hierarchie der Klasse java.awt.AWTEvent, die den Kategorien entsprechen, in die diese Ereignisse eingeteilt werden können.
Abbildung 12.3: Unterklassen von AWTEvent
Wie Sie sehen, bilden die InputEvent-Unterklassen nur einen kleinen Teil der AWTEvent-Hierarchie. In den folgenden Abschnitten erfahren Sie, welche Ereignis-Handler im JBuilder den Ereignissen dieser Unterklassen-Kategorien entsprechen. Die in diesen Unterklassen definierten Methodeen werden ebenfalls vorgestellt, aber beachten Sie, daß jede Unterklasse von ihrer Oberklasse erbt. Auch hier benennt JBuilder das Ereignis standardmäßig als e, Sie können also beispielsweise auf die Methode getModifiers() als e.getModifiers() zugreifen.
Eine vollständige Beschreibung dieser Klasse und ihrer Methoden finden Sie in der Online-Hilfe von Java.
Benutzeroberflächen-Komponenten erzeugen ein spezielles Ereignis, das sogenannte Aktionsereignise. In JBuilder wird eine Aktion einer Benutzeroberflächen-Komponente aufgefangen, indem der actionPerformed-Ereignis-Handler definiert wird. Hier der Methodenheader für einen actionPerformed-Ereignis-Handler, beispielsweise für die Komponente myButton:
void myButton_actionPerformed(ActionEvent e) {...}
Diese Ereignis-Handler nehmen ein ActionEvent-Objekt als Argument entgegen. Hier der Header der Konstruktormethode:
public ActionEvent(Object source, int id,
String command, int modifiers)
source ist das Objekt der Benutzeroberflächen-Komponente, das das Ereignis ausgelöst hat. id gibt den Typ der Aktion an (int-Konstante: ACTION_PERFORMED). modifiers gibt an, ob eine oder mehrere Modifier-Tasten gedrückt waren, als das Ereignis aufgetreten ist. Der command-Parameter ist der Wert der actionCommand-Eigenschaft der Komponente:
Das ActionEvent-Objekt hat die folgenden Methoden:
Angenommen, Sie wollen ein einfaches Applet mit sechs Schaltflächen mit den Farben des Regenbogens anlegen. Sie könnten für jede Schaltfläche einen eigenen Ereignis-Handler anlegen, aber in diesem Beispiel erzeugen Sie den actionPerformed()-Ereignis-Handler für die erste Schaltfläche und verwendendiesen auch für die anderen fünf Schaltflächen. Im Ereignis-Handler wird die Hintergrundfarbe des Applets geändert, je nachdem, welche Schaltfläche angeklickt wurde.
Fügen Sie dem heutigen Projekt das neue Applet ActionTest hinzu. Ändern Sie im Desig-Modus bei selektiertem this die background-Eigenschaft auf Gray, die layout-Eigenschaft auf FlowLayout und fügen Sie sechs Button-Komponenten ein. Abbildung 12.4 zeigt die Benutzeroberfläche des Applets.
Abbildung 12.4: Das Applet ActionTest
Selektieren Sie button1 und ändern Sie seine <name>-Eigenschaft auf redBtn, seine label-Eigenschaft auf Red. Beachten Sie, daß sich mit dem Bestätigen der label-Eigenschaft auch die actionCommand-Eigenschaft auf Red ändert. Standardmäßig ist das actionCommand für eine Button-Komponente dasselbe wie ihre label-Eigenschaft. Dadurch wird es einfach, mit der Methode getActionCommand() zu prüfen, welche Schaltfläche gedrückt wurde.
Klicken Sie die einzelnen Schaltflächen nacheinander an und ändern Sie die <name> und label-Eigenschaften wie in Tabelle 12.2 gezeigt.
Tabelle 12.2: Eigenschaften für das Abbildung ActionTest
Um den Ereignis-Handler für diese sechs Schaltflächen zu erzeugen, selektieren Sie die Komponente redBtn und klicken auf die Ereignisse-Registerkarte. Wenn Sie jetzt dreimal auf einen Handler klicken, erhält er den Namen redBtn_actionPeformed, abhängig von der selektierten Komponente. Aber Sie wollen einen Ereignis-Handler erzeugen, der für alle sechs Schaltflächen eingesetzt werden kann, Sie sollten ihm also einen generischeren Namen geben. Dazu klikken Sie auf das actionPerformed-JBuilder, das redBtn_actionPerformed als Methodennamen vorschlägt. Drücken Sie Home, um den Cursor an den Anfang des Methodennamens zu setzen, und ändern Sie red in color. Jetzt doppelklicken Sie, um den Methodenheader im Quellcode zu erzeugen.
In diesem Ereignis-Handler wollen Sie wissen, welche Schaltfläche das Ereignis ausgelöst hat. Durch Auswertung des von getActionCommand() zurückgegebenen Strings können Sie den Hintergrund des Applets auf die entsprechende Farbe setzen und es dann neuzeichnen. Weil die Methode einen String und keinen elementaren Datentyp zurückgibt, brauchen Sie verschachtelte if-else-Anweisungen statt eines switch. Hier folgt der Rumpf des Ereignis-Handlers colorBtn_actionPerformed():
String btnColor = e.getActionCommand();
if (btnColor.equals("Red"))
this.setBackground(Color.red);
else if (btnColor.equals("Orange"))
this.setBackground(Color.orange);
else if (btnColor.equals("Yellow"))
this.setBackground(Color.yellow);
else if (btnColor.equals("Green"))
this.setBackground(Color.green);
else if (btnColor.equals("Blue"))
this.setBackground(Color.blue);
else if (btnColor.equals("Purple"))
this.setBackground(Color.magenta);
repaint();
Immer wenn Sie auf eine der sechs Schaltflächen in diesem Applet klicken, wird der gemeinsam genutzte Ereignis-Handler ausgeführt und die Zeichenfläche des Applets ändert die Farbe. Listing 12.4 zeigt das Applet ActionTest.
1: import java.awt.*;
2: import java.awt.event.*;
3: import java.applet.*;
4: import borland.jbcl.layout.*;
5: import borland.jbcl.control.*;
6:
7: public class ActionTest extends Applet {
8: boolean isStandalone = false;
9: Button redBtn = new Button();
10: Button orangeBtn = new Button();
11: Button yellowBtn = new Button();
12: Button greenBtn = new Button();
13: Button blueBtn = new Button();
14: Button purpleBtn = new Button();
15: FlowLayout flowLayout1 = new FlowLayout();
16:
17: // Applet erzeugen
18: public ActionTest() {
19: }
20:
21: // Applet initialisieren
22: public void init() {
23: try { jbInit(); } catch (Exception e) { e.printStackTrace(); }
24: }
25:
26: // Initialisierung der Komponenten
27: public void jbInit() throws Exception{
28: this.setBackground(Color.gray);
29: redBtn.setLabel("Red");
30: redBtn.addActionListener(new
[ccc]ActionTest_redBtn_actionAdapter(this));
31: orangeBtn.setLabel("Orange");
32: orangeBtn.addActionListener(new
[ccc]ActionTest_orangeBtn_actionAdapter(this));
33: yellowBtn.setLabel("Yellow");
34: yellowBtn.addActionListener(new
[ccc]ActionTest_yellowBtn_actionAdapter(this));
35: greenBtn.setLabel("Green");
36: greenBtn.addActionListener(new
[ccc]ActionTest_greenBtn_actionAdapter(this));
37: blueBtn.setLabel("Blue");
38: blueBtn.addActionListener(new
[ccc]ActionTest_blueBtn_actionAdapter(this));
39: purpleBtn.setLabel("Purple");
40: purpleBtn.addActionListener(new
[ccc]ActionTest_purpleBtn_actionAdapter(this));
41: this.setLayout(flowLayout1);
42: this.add(redBtn, null);
43: this.add(orangeBtn, null);
44: this.add(yellowBtn, null);
45: this.add(greenBtn, null);
46: this.add(blueBtn, null);
47: this.add(purpleBtn, null);
48: }
49:
50: // Applet-Information ermitteln
51: public String getAppletInfo() {
52: return "Applet Information";
53: }
54:
55: // Parameter-Information ermitteln
56: public String[][] getParameterInfo() {
57: return null;
58: }
59:
60: void colorBtn_actionPerformed(ActionEvent e) {
61: String btnColor = e.getActionCommand();
62: if (btnColor.equals("Red"))
63: this.setBackground(Color.red);
64: else if (btnColor.equals("Orange"))
65: this.setBackground(Color.orange);
66: else if (btnColor.equals("Yellow"))
67: this.setBackground(Color.yellow);
68: else if (btnColor.equals("Green"))
69: this.setBackground(Color.green);
70: else if (btnColor.equals("Blue"))
71: this.setBackground(Color.blue);
72: else if (btnColor.equals("Purple"))
73: this.setBackground(Color.magenta);
74: repaint();
75: }
76: }
77:
78: class ActionTest_redBtn_actionAdapter
[ccc]implements java.awt.event.ActionListener {
79: ActionTest adaptee;
80:
81: ActionTest_redBtn_actionAdapter(ActionTest adaptee) {
82: this.adaptee = adaptee;
83: }
84:
85: public void actionPerformed(ActionEvent e) {
86: adaptee.colorBtn_actionPerformed(e);
87: }
88: }
89:
90: class ActionTest_orangeBtn_actionAdapter
[ccc]implements java.awt.event.ActionListener {
91: ActionTest adaptee;
92:
93: ActionTest_orangeBtn_actionAdapter(ActionTest adaptee) {
94: this.adaptee = adaptee;
95: }
96:
97: public void actionPerformed(ActionEvent e) {
98: adaptee.colorBtn_actionPerformed(e);
99: }
100: }
101:
102: class ActionTest_yellowBtn_actionAdapter
[ccc]implements java.awt.event.ActionListener {
103: ActionTest adaptee;
104:
105: ActionTest_yellowBtn_actionAdapter(ActionTest adaptee) {
106: this.adaptee = adaptee;
107: }
108:
109: public void actionPerformed(ActionEvent e) {
110: adaptee.colorBtn_actionPerformed(e);
111: }
112: }
113:
114: class ActionTest_greenBtn_actionAdapter
[ccc]implements java.awt.event.ActionListener {
115: ActionTest adaptee;
116:
117: ActionTest_greenBtn_actionAdapter(ActionTest adaptee) {
118: this.adaptee = adaptee;
119: }
120:
121: public void actionPerformed(ActionEvent e) {
122: adaptee.colorBtn_actionPerformed(e);
123: }
124: }
125:
126: class ActionTest_blueBtn_actionAdapter
[ccc]implements java.awt.event.ActionListener {
127: ActionTest adaptee;
128:
129: ActionTest_blueBtn_actionAdapter(ActionTest adaptee) {
130: this.adaptee = adaptee;
131: }
132:
133: public void actionPerformed(ActionEvent e) {
134: adaptee.colorBtn_actionPerformed(e);
135: }
136: }
137:
138: class ActionTest_purpleBtn_actionAdapter
[ccc]implements java.awt.event.ActionListener {
139: ActionTest adaptee;
140:
141: ActionTest_purpleBtn_actionAdapter(ActionTest adaptee) {
142: this.adaptee = adaptee;
143: }
144:
145: public void actionPerformed(ActionEvent e) {
146: adaptee.colorBtn_actionPerformed(e);
147: }
148: }
MenuBar- und PopupMenu-Komponenten verwenden ebenfalls die label-Eigenschaft, um den Standard-actionCommand-Wert zu setzen. Detaillierte Informationen über die actionCommand-Werte für anderen AWT-Komponenten finden Sie in der Online-Dokumentation.
Das Ereignis adjustmentValueChanged ist im AWT für das Inkrement und Dekrement veränderbarer Objekte definiert, wie etwa Scrollbar. Der Methodenheader für einen adjustmentValueChanged-Ereignis-Handler könnte wie folgt aussehen:
void scrollbar1_adjustmentValueChanged(AdjustmentEvent e) {...}
Diese Ereignis-Handler nehmen ein AdjustmentEvent-Objekt entgegen. Hier der Header der Konstruktormethode:
public AdjustmentEvent(Adjustable source, int id,
int type, int value)
source ist die Komponente, die das Ereignis ausgelöst hat. id stellt den Typ der Anpassung dar (int-Konstante: ADJUSTMENT_VALUE_CHANGED). type gibt an, welche Anpassung in dem Ereignis aufgetreten ist, dabei kann eine von fünf Konstanten verwendet werden: UNIT_INCREMENT, UNIT_DECREMENT, BLOCK_INCREMENT, BLOCK_DECREMENT oder TRACK. value ist ein Integer, der die Einheit angibt, die für die Anpassung verwendet wird.
Das AdjustmentEvent-Objekt hat die folgenden Methoden:
Um dieses Ereignis zu beobachten, erzeugen Sie das Applet ScrollTest. Fügen Sie ein Label und ein Scrollbar ein und ändern Sie die Eigenschaften wie in Tabelle 12.3 gezeigt.
Tabelle 12.3: Eigenschaften für das Applet ScrollTest
Wenn Sie fertig sind, klicken Sie auf valueSbar, klicken auf die Ereignisse-Seite und klicken dreimal auf das Ereignis adjustmentValueChanged. Jetzt fügen Sie der Methode in Ihrem Quellcode die folgenden Zeilen hinzu:
int v = e.getValue();
valueSBar.setValue(v);
valueLbl.setText(String.valueOf(v));
Die erste Zeile ermittelt den Wert der Anpassung aus dem AdjustmentEvent-Objekt. Die zweite Zeile setzt die value-Eigenschaft der valueSbar-Komponente. Die dritte Zeile setzt den Text von valueLbl auf die Stringdarstellung dieses Werts. Wenn Sie das Applet ScrollTest ausführen, wird der aktuelle Wert des Schiebereglers in valueLbl reflektiert, wie in Abbildung 12.5 gezeigt.
Abbildung 12.5: Das Applet ScrollTest
Den vollständigen Quellcode für ScrollTest finden Sie in Listing 12.5.
1: import java.awt.*;
2: import java.awt.event.*;
3: import java.applet.*;
4: import borland.jbcl.layout.*;
5: import borland.jbcl.control.*;
6:
7: public class ScrollTest extends Applet {
8: XYLayout xYLayout1 = new XYLayout();
9: boolean isStandalone = false;
10: Label valueLbl = new Label();
11: Scrollbar valueSBar = new Scrollbar();
12:
13: //Get a parameter value
14: public String getParameter(String key, String def) {
15: return isStandalone ? System.getProperty(key, def) :
16: (getParameter(key) != null ? getParameter(key) : def);
17: }
18:
19: // Applet erzeugen
20: public ScrollTest() {
21: }
22:
23: //Initialize the applet
24: public void init() {
25: try { jbInit(); } catch (Exception e) { e.printStackTrace(); }
26: }
27:
28: // Komponenten initialisieren
29: public void jbInit() throws Exception{
30: this.setBackground(Color.cyan);
31: this.setLayout(xYLayout1);
32: this.add(valueLbl, new XYConstraints(21, 21, 54, 30));
33: this.add(valueSBar, new XYConstraints(96, 21, 270, 30));
34: xYLayout1.setWidth(400);
35: xYLayout1.setHeight(300);
36: valueLbl.setFont(new Font("TimesRoman", 1, 24));
37: valueLbl.setAlignment(2);
38: valueLbl.setText("0");
39: valueSBar.setOrientation(0);
40: valueSBar.addAdjustmentListener(new
[ccc]ScrollTest_valueSBar_adjustmentAdapter(this));
41: }
42:
43: // Applet-Information ermitteln
44: public String getAppletInfo() {
45: return "Applet Information";
46: }
47:
48: // Parameter-Information ermitteln
49: public String[][] getParameterInfo() {
50: return null;
51: }
52:
53: void valueSBar_adjustmentValueChanged(AdjustmentEvent e) {
54: int v = e.getValue();
55: valueSBar.setValue(v);
56: valueLbl.setText(String.valueOf(v));
57: }
58: }
59:
60: class ScrollTest_valueSBar_adjustmentAdapter
[ccc]implements java.awt.event.AdjustmentListener {
61: ScrollTest adaptee;
62:
63: ScrollTest_valueSBar_adjustmentAdapter(ScrollTest adaptee) {
64: this.adaptee = adaptee;
65: }
66:
67: public void adjustmentValueChanged(AdjustmentEvent e) {
68: adaptee.valueSBar_adjustmentValueChanged(e);
69: }
70: }
Komponentenereignisse sind im AWT definiert, so daß Sie erkennen können, ob eine Komponente verborgen, angezeigt, verschoben oder in der Größe verändert wurde. Der AWT verarbeitet das Verschieben, Größenändern und Anzeigen von Komponenten automatisch, aber es gibt Situationen, wo Sie basierend auf diesen Ereignisen eine zuästzliche Funktionalität einfügen wollen. Der Konstruktor ComponentEvent ist einfach:
public ComponentEvent(Component source, int id)
Er gibt die Quelle des Ereignisses an, source, sowie seine ID (int-Konstanten: COMPONENT_HIDDEN, COMPONENT_MOVED, COMPONENT_RESIZED, COMPONENT_SHOWN). Er hat eine getComponent()-Methode, die das Objekt zurückgibt, das das Ereignis erzeugt hat (den Wert des source-Parameters).
Alle Komponenten haben diese vier Ereignisse auf ihrer Ereignisse-Seite: componentHidden, componentMoved, componentResized und componentShown, die den id-Parameter-Konstanten des ComponentEvent-Objekts entsprechen. Wenn Sie ich Ihrem Quellcode einen Ereignis-Handler einfügen, sieht die Methodensignatur wie folgt aus:
void textarea1_ComponentResized(ComponentEvent e) {...}
Auch hier können Sie auf die ComponentEvent-Methoden zureifen, indem Sie die Syntax e.methodenName anwenden.
Fokusereignisse sind im AWT definiert, damit Sie erkennen können, ob eine Komponente den Fokus erhalten hat (also die aktive Komponente ist), oder ob sie den Fokus verloren hat. Hier der Konstruktor FocusEvent:
public FocusEvent(Component source, int id,
boolean temporary)
Er gibt die Quelle des Ereignisses an, source, sowie seine id (int-Konstanten: FOCUS_GAINED und FOCUS_LOST). Darüber hinaus gibt es den temporary-Parameter, der angibt, ob das FocusEvent ein temporärer Wechsel war, was auftritt, wenn Komponenten aufgrund anderer Operationen vorübergehend den Fokus erhalten. Der permanente Fokus wird beispielsweise erteilt, wenn ein Anwender in einem Dialog auf eine Komponente springt. Diese Ereignisklasse definiert eine isTemporary()-Methode, die true zurückgibt, wenn FocusEvent temporär ist, false, wenn es permanent ist.
Die meisten Komponenten haben focusGained und focusLost auf ihrer Ereignisse-Seite, was den id-Konstanten für das FocusEvent-Objekt entspricht. Wenn Sie in Ihrem Quellcode einen Ereignis-Handler erzeugen, könnten die Methodensignatur wie folgt aussehen:
void checkbox1_focusGained(FocusEvent e) {...}
Auch auf die ComponentEvent-Methoden wird über die Syntax e.methodenName zugegriffen.
itemStateChanged ist im AWT definiert, damit Sie erkennen können, ob ein Element selektiert ist, etwa Elemente in einer List- oder Choice-Komponente. Der Methodenheader für einen Ereignis-Handler einer List-Komponente könnte wie folgt aussehen:
void list1_ itemStateChanged(ItemEvent e) {...}
Diese Ereignis-Handler nehmen als Argument ein ItemEvent-Objekt entgegen. Hier der Header der Konstruktormethode:
public ItemEvent(ItemSelectable source, int id,
Object item, int stateChange)
source ist die Komponente, die das Ereignis ausgelöst hat. id ist eine Integer-Konstante, ITEM_STATE_CHANGED, die dem Ereignis itemStateChanged entspricht. Der object-Parameter gibt an, welches Element das Ereignis verursacht hat. Der stateChange-Parameter nimmt eine von zwei Konstanten an: SELECTED oder DESELECTED. Die Methoden des ItemEvent-Objekts sind unter anderem:
Der Methodenzugriff erfolgt über die Syntax e.methodenName.
Fensterereignisse ermöglichen Ihnen, den aktuellen Status eines Frames auf Ihrer Benutzeroberfläche zu ermitteln. Hier der WindowEvent-Konstruktor:
public WindowEvent(Window source, int id)
source ist die Quelle des Ereignisses, und die id des Ereignisses kann durch die folgenden Integer-Konstanten dargestellt werden:
Diese Konstanten entsprechen den Frame-Ereignissen, windowActivated, windowClosed, windowClosing, windowDeactivated, windowDeiconified, windowIconified und windowOpened. Diese Ereignisklasse definiert eine getWindow()-Methode, die das in der Instanzvariablen source gespeicherte Fenster zurückgibt.
Es ist ganz einfach, im JBuilder Ereignisse zu verarbeiten, weil die Ereignisse-Registerkarte des Inspektors alle wichtigen Ereignisse für jede selektierte Komponente anzeigt. Wenn Sie dreimal auf das Ereignis klicken, wird ein Methodenheader für Sie in de Code eingefügt, wo Sie Ihren Code einfügen können. Mit dem Ereignis-Handler fängt das Programm automatisch die Ereignisse auf.
F Im Lines-Applet werden die Koordinaten für Startpunkt und Endpunkt in Arrays abgelegt, die eine feste Größe haben. Kann ich das Applet so abändern, daß es unendlich viele Linien zeichnet?
A Verwenden Sie die Vector-Klasse. Vector ist Teil des java.util-Pakets und implementiert ein Array, das automatisch anwächst - wie eine verkettete Liste in anderen Sprachen. Der Nachteil von Vector ist, daß seine Elemente Objekte sein müssen. Das bedeutet, Sie müssen int-Werte in Integer-Objekte umwandeln, um sie in den Vector einfügen zu können. Sie können die Elemente von Vector jedoch einfach über dessen Methoden manipulieren. Wenn Sie ein Array variabler Größe brauchen, verwenden Sie Vector.
Der Workshop bietet zwei Möglichkeiten, zu überprüfen, was Sie in diesem Kapitel gelernt haben. Der Quiz-Teil stellt Ihnen Fragen, die Ihnen helfen sollen, Ihr Verständnis für den vorgestellten Stoff zu vertiefen. Die Antworten auf die Fragen finden Sie in Anhang A. Der Übungen-Teil ermöglicht Ihnen, Erfahrungen in der Anwendung der Dinge zu sammeln, die Sie hier kennengelernt haben. Versuchen Sie, diese Dinge durchzuarbeiten, bevor Sie mit der nächsten Lektion weitermachen.