6. Eventhandling in Java OO-Graphics in Java Eventhandling in Java 143
Eventhandling in Java Bisher: OO-Grundlagen, Programmablauf, Zeichenmöglichkeiten, Anordnung von Bedienelementen. Was fehlt? Interaktivität!!! OO-Graphics in Java Eventhandling in Java 144
Worauf ein Programm reagieren muss Low-Level: Tastatureingaben, Maus-Ereignisse, Timer-Ereignisse. High-Level: Fenster schliessen/öffnen, Grössenveränderungen, Knopf auf Bildschirm gedrückt, Text editiert, OO-Graphics in Java Eventhandling in Java 145
Java 1.1 vs. Java 1.0 Achtung (wichtige Warnung): Das Eventhandling von Java 1.1 unterscheidet sich wesentlich vom Eventhandling in Java 1.0. Java 1.0 Stil ist in Java 1.1 zwar noch möglich, aber nicht empfohlen (deprecated). Im folgenden wird Java 1.1 Stil vermittelt. Java 1.1 wird von Netscape 4.06, von Internet Explorer 4.01 und von Hotjava (Sun Browser) unterstützt. OO-Graphics in Java Eventhandling in Java 146
Event Event: Das Eintreten eines Ereignisses, auf welches das Programm reagieren muss (z.b. Tastendruck, Mausbewegung, ). Event-Quelle: Events werden immer dem Component-Objekt zugeordnet, in dem sie entstehen der Event-Quelle. Event-Objekt: Das Auftreten eines Events ist verbunden mit der Erzeugung eines Objektes. Dieses Objekt gehört einer der Unterklassen von AWTEvent an. Es enthält alle notwendigen Informationen über das Event. Event-Listener: Component-Objekte speichern eine Liste von EventListener-Objekten ab. Dies sind Objekte, die über das Auftreten eines Events benachrichtigt werden sollen. Die Listener Objekte sind jeweils spezialisiert auf bestimmte Event-Klassen. Event-Action: Beim Auftreten eines Events veranlasst die Event- Quelle den Aufruf einer standardisierten (dem Event zugeordneten) Methode bei allen für diesen Event-Typ angemeldeten Listener-Objekten. Der Aufruf dieser Methoden ist dem Event selbst gleichzusetzen! OO-Graphics in Java Eventhandling in Java 147
Das awt.event package Object java.lang EventObject java.util AWTEvent AWTEventMulticaster Serializable java.io-objects Thread java.lang java.awt-events s ActionListener AdjustmentListener Event EventQueue EventDispatchThread local to package EventQueueItem local to package java.awt.event 1995-7, Charles L. Perkins http://rendezvous.com/java ComponentListener ComponentAdapter ContainerListener ContainerAdapter FocusListener FocusAdapter EventListener java.util ItemListener KeyListener KeyAdapter MouseAdapter MouseListener MouseMotionAdapter MouseMotionListener WindowAdapter TextListener WindowListener ActionEvent ContainerEvent Object java.lang EventObject java.util AWTEvent java.awt-events AdjustmentEvent ComponentEvent ItemEvent FocusEvent InputEvent PaintEvent KeyEvent MouseEvent Serializable java.io-objects TextEvent WindowEvent OO-Graphics in Java Eventhandling in Java 148
Event-Objekte AWTEvent-Objekt ist ein Objekt welches das Auftreten eines Ereignisses beschreibt, enthält alle notwendigen Informationen, die das Ereignis betreffen (Wo? Wann? Wer? ), ist quasi ein Brief von der Ereignisquelle an alle Interessenten. besitzt zahlreiche Unterklassen, die spezialisierte Ereignisse beschreiben (MouseEvent, MouseMotionEvent, KeyEvent, WindowEvent, ActionEvent, ) OO-Graphics in Java Eventhandling in Java 149
Event Zyklus in Java-1.1 Erzeugung: Component-Objekte sind die Event- Quellen. Tritt ein zu einer Component gehöriges Ereignis auf (z.b. Knopf-gedrückt auf einem Button oder Mouse-Drag in einer Canvas), so wird ein entsprechendes AWTEvent-Objekt erzeugt. Verschicken: Jede Component hat eine Liste von EventListener-Objekten. An diese wird das AWTEvent verschickt (d.h. bestimmte Methoden werden aufgerufen). Verarbeitung: Die EventListener-Objekte müssen Methoden definieren, die auf das Verschicken des Ereignisses reagieren können. Ein EventListener kann ein Event als abgearbeitet markieren. Consumed: Ein AWTEvent-Objekt ist aufgebraucht (consumed), wenn es an alle potentiellen Listener verschickt wurde. OO-Graphics in Java Eventhandling in Java 150
Was passiert, wenn ein Knopf gedrückt wird? Press Me Knopf mittels Maus aktiviert Button Mouseclick veranlasst den Button ein AWTEvent: ActionEvent zu erzeugen. Dies Event wird an alle ActionEventListener des Buttons geschickt listener.actionperformed(event) event ActionEvent Hat alle Information bzgl. Event- u.eventquelle und einen Identifier der ausgefuehrten Aktion. MyAction- Listener implementiert die Methode actionperformed() in welcher festgelegt ist, was bei Eintreten des Events passieren soll Die Klasse MyActionListener ist das einzige selbstgeschriebene Objekt in diesem Beispiel. OO-Graphics in Java Eventhandling in Java 151
MyActionListener Im selbst geschriebenen Code von MyActionListener ist festgelegt, was beim Auftreten eines ActionEvents geschehen soll. Die Klasse MyActionListener implementiert das Interface ActionListener. Dies erzwingt, dass in der Klasse MyActionListener die Methode actionperformed implementiert ist. Source-Code Gerüst: import java.awt.event.*; public class MyActionListener implements ActionListener{ public void actionperformed(actionevent e){...... OO-Graphics in Java Eventhandling in Java 152
Event Methodenaufruf Ein Event ist der Aufruf einer Methode in einem EventListener. Bei dem Methodenaufruf wird ein Objekt der Klasse AWTEvent als Parameter übergeben. Das AWTEvent-Objekt enthält weitere Information über das eingetretene Event. OO-Graphics in Java Eventhandling in Java 153
Programm-Beispiel für ActionEvent Ziel: Ein Button, der eine Zählvariable hochzählt und deren Inhalt auf dem Bildschirm anzeigt. Code für das Applet: import java.awt.*; import java.awt.event.*; import java.applet.*; // verwendete Packages public class CountApplet extends Applet { public int count=0; public Label label = new Label("0"); public void init() { setlayout(new FlowLayout()); Button b = new Button("Press Me"); b.addactionlistener(new MyActionListener(this)); add(b); add(label); // <---ADD LISTENER Hier werden in der Initialisierung lediglich der Button und das Label zum Anzeigen bereitgestellt. Der Button erhält einen selbstdefinierten ActionListener namens MyActionListener. OO-Graphics in Java Eventhandling in Java 154
Der Code für MyActionListener Der Listener MyActionListener erhöht beim Auftreten des ActionEvents die Zählervariable count des Applets. Dann veranlasst er, dass der zugehörige Text erzeugt wird, und erzwingt ein repaint des Applets. Code für den Listener: import java.awt.event.*; public class MyActionListener implements ActionListener{ private CountApplet app; MyActionListener(CountApplet app) { this.app=app; public void actionperformed(actionevent e){ app.count++; String s=(new Integer(app.count)).toString(); app.label.settext(s); app.label.invalidate(); // Layout ist ungültig app.validate(); // erzwinge neues Layout app.repaint(); // Zeichenanforderung Press Me 5 OO-Graphics in Java Eventhandling in Java 155
Erweiterte Version zum Auf- und Abzählen public class CountApplet extends Applet { public int count=0; public Label label = new Label("0"); public void init() { setlayout(new FlowLayout()); Button b1 = new Button("Increment"); b1.addactionlistener(new MyActionListener(1,this)); Button b2 = new Button("Decrement"); b2.addactionlistener(new MyActionListener(-1,this)); add(b1); add(b2); add(label); public class MyActionListener implements ActionListener{ CountApplet app; private int step; MyActionListener(int st,countapplet app) { this.app =app; step=st; public void actionperformed(actionevent e){ app.count=app.count+step; String s=(new Integer(app.count)).toString(); app.label.settext(s); app.label.invalidate(); app.validate(); Increment Decrement 5 app.repaint(); OO-Graphics in Java Eventhandling in Java 156
Übergabe von Information Im Beispiel des Applets CountApplet kam es lediglich darauf an, dass überhaupt ein ActionEvent auftrat. Es wurde keine Information aus dem Event-Objekt entnommen. (In unserer Briefmetapher : Allein das Eintreffen des Briefes löste die Reaktion (hochzählen) aus. Der Brief musste gar nicht erst gelesen werden.) Oftmals ist es allerdings notwendig, die im Event übergebene Information abzufragen. Als Informationsbehälter stellt AWTEvent diverse spezialisierte Unterklassen bereit. OO-Graphics in Java Eventhandling in Java 157
Count-Applet mit Lesen des Events Die folgende Increment/Decrement-Version stellt durch Lesen der Button-Beschriftung fest, ob ab- oder aufgezählt werden soll. Code des MouseListeners: import java.awt.event.*; public class MyActionListener implements ActionListener{ private CountApplet app; MyActionListener(CountApplet app){ this.app=app; public void actionperformed(actionevent e){ if (e.getactioncommand().equals("increment")) {//<<<< LESEN app.count=app.count+1; if (e.getactioncommand().equals("decrement")) {//<<<< LESEN app.count=app.count-1; String s=(new Integer(app.count)).toString(); app.label.settext(s); app.label.invalidate(); app.validate(); app.repaint(); OO-Graphics in Java Eventhandling in Java 158
Unterklassen von AWTEvent Object ActionEvent ContainerEvent AdjustmentEvent FocusEvent MouseEvent AWTEvent ComponentEvent InputEvent KeyEvent ItemEvent PaintEvent TextEvent WindowEvent instantiierbares Objekt nicht instantiierbares abstraktes Objekt Die Unterklassen von AWTEvent sind spezialisierte Datenbehälter, für die verschiedenen Ereignisse. OO-Graphics in Java Eventhandling in Java 159
Beispiel: Methoden von MouseEvent (I) MouseEvent hat in der Klassenhierarchie die Position AWTEvent ComponentEvent InputEvent MouseEvent MouseEvent besitzt u.a. die folgenden Methoden: getclickcount(): Anzahl der Mouseclicks. getpoint(): x y -Position des Events relativ zur Quell-component. getx(): x-komponente des Events relativ zur Quell-component. gety(): y-komponente des Events relativ zur Quell-component. ispopuptrigger(): Erzeugt das Event ein Pop-Up-Menu? translatepoint(int, int): Verändert das Koordinatensystem des Events. OO-Graphics in Java Eventhandling in Java 160
Beispiel: Methoden von MouseEvent (II) Die Oberklassen vom MouseEvent stellen zudem u.a. folgende Methoden zur Verfügung: InputEvent: getmodifiers(): Liefert Modifizier-Flags für das Ereignis. getwhen(): Systemzeit zu der das Ereignis stattfand. isaltdown(), iscontroldown(), ismetadown(), isshiftdown(): Wurden modifizierende Tasten gedrückt? ComponentEvent: getcomponent(): Quell-Component, die das Event verursacht hat. AWTEvent: getid(): Event-Typ Event: getsource(): Event-Quelle OO-Graphics in Java Eventhandling in Java 161
Listener Listener sind Interfaces welche bestimmte Ereignisklassen gegeneinander abgrenzen (z.b. die Klasse der ActionEvents, MouseEvents, ), legen Methoden fest, auf die man für eine Ereignisklasse reagieren können muss (z.b. actionperformed() für ActionEvents), hat folgende Unterinterfaces: ActionListener, AdjustmentListener, ComponentListener, ContainerListener, FocusListener, ItemListener, KeyListener, MouseListener, MouseMotionListener, TextListener, WindowListener. Components-Objekte sind mit addxlistener- Methoden ausgestattet, mittels derer ein XListener angemeldet werden kann (z.b. addactionlistener(mylistener) um mylistener als ActionListener anzumelden). OO-Graphics in Java Eventhandling in Java 162
Methoden der Listener Listener Methoden mögliche Components ActionListener actionperformed Button List MenuItem TextField AdjustmentListener adjustmentvaluechanged Scrollbar ComponentListener componenthidden Component componentmoved componentresized componentshown ContainerListener componentadded Container componentremoved FocusListener focusgained Component focuslost ItemListener itemstatechanged Checkbox CheckboxMenuItem Choice List KeyListener keypressed Component keyreleased keytyped MouseListener mouseclicked Component mouseentered mouseexited mousepressed mousereleased MouseMotionListener mousedragged Component mousemoved TextListener textvaluechanged TextComponent WindowListener windowactivated Window windowclosed windowclosing windowdeactivated windowdeiconified windowiconified windowopened OO-Graphics in Java Eventhandling in Java 163
Beispiel: Ein Draw-Applet (erste Version) Aufgabe: Ein Applet DrawApplet, welches eine Zeichenoberfläche besitzt, auf die man mit der Maus zeichnen kann. Das Zeichnen soll nur bei gedrückter Maustaste erfolgen. Erster Ansatz (Applet -Code): import java.awt.*; import java.awt.event.*; import java.applet.*; public class DrawApplet extends Applet { public Canvas canv = new Canvas(); public void init() { setlayout(new BorderLayout()); canv.setsize(400,400); canv.setbackground(color.blue.darker()); canv.setforeground(color.yellow); add("center",canv); MyMouseListener listener = new MyMouseListener(); canv.addmouselistener(listener); canv.addmousemotionlistener(listener); OO-Graphics in Java Eventhandling in Java 164
Der MouseListener (I) import java.awt.*; import java.awt.event.*; public class MyMouseListener implements MouseListener, MouseMotionListener{ public Point p=new Point(0,0); MyMouseListener() { public void mouseclicked(mouseevent e){ public void mouseentered(mouseevent e){ public void mouseexited(mouseevent e){ public void mousemoved(mouseevent e){ public void mousereleased(mouseevent e){ public void mousepressed(mouseevent e){ p= new Point(e.getPoint()); public void mousedragged(mouseevent e){ Canvas canv = (Canvas)e.getSource(); Graphics g = canv.getgraphics(); g.drawline(p.x,p.y,e.getx(),e.gety()); p= new Point(e.getPoint()); Ein mousedragged Ereignis bewirkt sofortiges Malen auf der appleteigenen Canvas canv. OO-Graphics in Java Eventhandling in Java 165
Kritik an der ersten Version Die gemalte Zeichnung ist nirgends abgespeichert. Ein paint (welches vom Window-Manager jederzeit geschickt werden kann) bewirkt ein sofortiges Löschen der Zeichnung. Abhilfe: Die Zeichnung wird irgendwo gespeichert (entweder als bitmap oder in Form der Koordinaten der gemalten Linienstücke). Man schreibt eine Unterklasse MyCanvas der vom AWT bereitgestellten Klasse Canvas. Die Unterklasse MyCanvas besitzt eine eigene paint()-methode, die für das Malen der bisherigen Zeichnung sorgt. OO-Graphics in Java Eventhandling in Java 166
Draw-Applet zweite Version Code für DrawApplet und für MyCanvas: import... public class DrawApplet extends Applet { public MyCanvas canv = new MyCanvas(); // <<<< AENDERUNG!!!! public void init() { setlayout(new BorderLayout()); canv.setsize(400,400); canv.setbackground(color.blue.darker()); canv.setforeground(color.yellow); add("center",canv); MyMouseListener listener= new MyMouseListener(canv);//<<< AENDERUNG canv.addmouselistener(listener); canv.addmousemotionlistener(listener); import java.awt.*; import java.util.*; public class MyCanvas extends Canvas { public Vector startpoints = new Vector(); public Vector endpoints = new Vector(); public void paint(graphics g) { for (int i=0;i<startpoints.size();i=i+1){ Point p1=(point)startpoints.elementat(i); Point p2=(point)endpoints.elementat(i); g.drawline(p1.x,p1.y,p2.x,p2.y); // Lokaler Speicher // Lokaler Speicher // Zeichenmethode OO-Graphics in Java Eventhandling in Java 167
Der MouseListener (II) import... public class MyMouseListener implements MouseListener, MouseMotionListener{ private MyCanvas canv; // <<<< AENDERUNG!!!! public Point p=new Point(0,0); MyMouseListener(MyCanvas a){ // <<<< AENDERUNG!!!! canv=a; public void mouseclicked(mouseevent e){ public void mouseentered(mouseevent e){ public void mouseexited(mouseevent e){ public void mousemoved(mouseevent e){ public void mousereleased(mouseevent e){ public void mousepressed(mouseevent e){ p= new Point(e.getPoint()); public void mousedragged(mouseevent e){ canv.startpoints.addelement(p); // Abspeichern statt Zeichnen p= new Point(e.getPoint()); canv.endpoints.addelement(p); // Abspeichern statt Zeichnen canv.repaint(); // Zeichnen erzwingen Der wesentliche Unterschied gegenüber der ersten Version besteht darin, dass nicht mehr direkt auf einer Canvas gemalt wird. Vielmehr wird die Zeicheninformation nur noch durch MyMouseListener in MyCanvas abgespeichert und von ihr bei Bedarf gemalt. OO-Graphics in Java Eventhandling in Java 168
Kritik an der zweiten Version Der Bildschirm flackert!!! Durch die geänderte Zeichenstrategie ist nun bei jedem einzelnen mousedragged Ereignis der (schrittweise) Aufbau der kompletten Zeichnung zu sehen. Die geschieht im allgeneinen zwar sehr schnell, ist bei aufwendigeren Zeichnungen aber als Flackern wahrnehmbar. Abhilfe: Einführung von double-buffering. Der Bildaufbau erfolgt unsichtbar im Hintergrund auf einem eigens dafür bereitgestellten Stück Speicher (bitmap). Die notwendigen Änderungen können alle lokal in der Klasse MyCanvas vorgenommen werden. OO-Graphics in Java Eventhandling in Java 169
Double buffering Vordergrund Bildaufbau kopieren Das neue Bild wird auf einer bitmap (im Speicher) gemalt. Erst, wenn das Bild fertig ist, wird es im sichtbaren Fenster dargestellt. OO-Graphics in Java Eventhandling in Java 170
MyCanvas mit double-buffering public class MyCanvas extends Canvas { public Vector startpoints = new Vector(); public Vector endpoints = new Vector(); int oldw, oldh; Image backimage; Graphics backg; //Hintergrundbild //Graphics von backimage public void paint(graphics g) { Dimension d = getsize(); if (d.width!= oldw d.height!= oldh ) { //Neuer Speicher notwendig? if (backimage!= null) backimage.flush(); backimage = createimage(d.width,d.height); backg = backimage.getgraphics(); oldw = d.width; oldh = d.height; backg = backimage.getgraphics(); backg.setcolor(getbackground()); backg.fillrect(0,0,oldw,oldh); backg.setcolor(getforeground()); for (int i=0;i<startpoints.size();i=i+1){ Point p1=(point)startpoints.elementat(i); Point p2=(point)endpoints.elementat(i); backg.drawline(p1.x,p1.y,p2.x,p2.y); g.drawimage(backimage,0,0,this); //Alles im Hintergrund malen //nach vorne kopieren public void update(graphics g) { //muss ueberschrieben werden paint OO-Graphics in Java Eventhandling in Java 171
Checkbox CheckboxGroup Oft ist es notwendig mehrere Schalter zu erzeugen, mittels derer man zwischen verschiedenen Betriebszuständen des Programmes umschalten kann. Der folgende Code erzeugt Radio-Button Verhalten: import java.applet.applet; import java.awt.*; public class CheckBoxApplet extends Applet { public void init() { setbackground(color.lightgray); Panel controls = new Panel(new GridLayout(1,3)); CheckboxGroup cg = new CheckboxGroup(); Checkbox a = new Checkbox("First" ); a.setcheckboxgroup(cg); Checkbox b = new Checkbox("Second" ); b.setcheckboxgroup(cg); Checkbox c = new Checkbox("Third" ); c.setcheckboxgroup(cg); a.setstate(true); controls.add(a); controls.add(b); controls.add(c); add(controls); OO-Graphics in Java Eventhandling in Java 172
Eventhandling bei Radio-Buttons Aufgabe: Drei Knöpfe mit Radio-Button Verhalten sollen jeweils individuellen Text im Fenster anzeigen. import java.applet.applet; import java.awt.*; public class CheckBoxApplet extends Applet { public void init() { setbackground(color.lightgray); Label label = new Label("?????????????????"); label.setfont(new Font("Helvetica",Font.BOLD,36)); Panel controls = new Panel(new GridLayout(1,3)); MyCheckboxGroup cg = new MyCheckboxGroup(); MyCheckbox a = new MyCheckbox("First","Erster",label); a.setcheckboxgroup(cg); MyCheckbox b = new MyCheckbox("Second","Zweiter",label ); b.setcheckboxgroup(cg); MyCheckbox c = new MyCheckbox("Third","Dritter",label ); c.setcheckboxgroup(cg); a.setstate(true); controls.add(a); controls.add(b); controls.add(c); add(controls); add(label); OO-Graphics in Java Eventhandling in Java 173
Code für MyCheckbox import java.awt.*; public class MyCheckbox extends Checkbox { String pt; Label l; private MyCheckbox() { public MyCheckbox(String text, String printtext, Label label) { setlabel(text); pt=printtext; l=label; public void deselect( ) { // Hier darf man eigenes // Verhalten spezifizieren public void select( ) { l.settext(pt); // Hier darf man eigenes // Verhalten spezifizieren Die Checkbox wird mit einem select/deselect- Mechanismus ausgestatted. Die Steuerung dieses Mechanismus wird von der CheckboxGroup übernommen. (Hiermit wird zwar das interne Eventhandling umgangen, dies ist jedoch sinnvoll. Auf diese Weise wird ein deselect-verhalten ermöglicht.) OO-Graphics in Java Eventhandling in Java 174
Code für MyCheckboxGroup import java.awt.*; import java.awt.event.*; class MyCheckboxGroup extends CheckboxGroup { public synchronized void setselectedcheckbox(checkbox checkbox) { Checkbox c2 =getselectedcheckbox(); if (c2!= null && c2 instanceof MyCheckbox) { ((MyCheckbox)c2).deselect(); super.setselectedcheckbox(checkbox); ((MyCheckbox)checkbox).select(); Die setselectedcheckbox-methode wird vom AWT beim Drücken eines Knopfs der Buttongroup aufgerufen. Dies ist eine geeignete Stelle um den select/deselect- Mechanismus einzufügen, indem wir das normale Verhalten der Methode setselectedcheckbox aus der Klasse CheckboxGroup mit unserem speziellen Verhalten überschreiben. OO-Graphics in Java Eventhandling in Java 175
OO-Graphics in Java Eventhandling in Java 176