Learning By Doing Ereignissteuerung (Events) ereignisgesteuert m m - - prozedural r a m u l a g r o -P m f r a m u l a g r o a b P g l a r o a b m - P f u l a g r o a b r a m C a llb a c k m e th o d e P f u l a g r o a b r a m m U n te rp ro g ra m m (M eth o d e ) P a b f r a m u l a g r o -P a b f m Event kann irgendwo auftreten u an fest codierter Stelle r a m Unterprogrammaufruf f H a u p tp ro g ra m m H a u p tp ro g ra m m Wann immer der Event auftritt, führe möglichst bald aus ... Learning By Doing TimerEvent (UML-Diagramm) im Delegations-Eventmodell <interface> TimerListener Garantieerklärung: timeElapsed() existiert! timeElapsed() LoResAlarmTimer has-a TimerListener timerListener addTimerListener() ... Event! Aufruf von timerListener.timeElapsed() implements DigitalWatch LoResAlarmTimer timer int time Implementierung der Callbackmethode DigitalWatch() timeElapsed() main() has-a Registrierung der Callbackmethode Registrierung: Übergeben einer Referenz der Klasse, welche die Callbackmethode enthält, an den Eventhandler, der die Callbackmethode bei jedem Event aufruft. Zur Registrierung der Callbackmethode Learning By Doing // DigitalWatch.java import ch.aplu.util.*; import java.awt.Font; public class DigitalWatch implements TimerListener { private int seconds = 0; private boolean isBell = true; private LoResAlarmTimer timer = new LoResAlarmTimer(1000000L); private GPanel panel = new GPanel(); public DigitalWatch() { panel.font(new Font( "Arial", Font.PLAIN, 200)); timer.addTimerListener(this); while (true) { if (isBell) { { isBell isBell = = false; false; panel.clear(); panel.text(0.3, 0.4, 0.4, panel.text(0.3, Integer.toString(seconds)); seconds++; seconds++; } } } } Implementierung "DigitalWatch implementiert einen TimerListener" Registrierung "Dieser TimerListener wird beim Eventhandler registriert" Eventloop Callbackmethode public boolean timeElapsed() { isBell = true; return true; } public static void main(String[] args) { new DigitalWatch(); } } Learning By Doing // WbzEx11.java import java.awt.event.*; import java.awt.Color; import ch.aplu.util.*; Mausevents Interface MouseListener mouseClicked() mouseEntered() mouseExited() mousePressed() mouseReleased() Innere Klasse hat Zugriff Callbackmethode implements MouseAdapater void mouseClicked(MouseEvent e) {} void mouseEntered(MouseEvent e) {} void mouseExited(MouseEvent e) {} void mousePressed(MouseEvent e) {} void mouseReleased(MouseEvent e) {} public class WbzEx11 { class MyMouseAdapter extends MouseAdapter { public void mousePressed(MouseEvent evt) { Color c = new Color((float)Math.random(), (float)Math.random(), (float)Math.random()); Stern stern = new Stern(p, 50, c); stern.moveAt((int)p.toWindowX(evt.getX()), (int)p.toWindowY(evt.getY())); stern.showMe(); } } private GPanel p = new GPanel(0, 500, 0, 500); is-a MyMouseAdapater void mousePressed(MouseEvent e) { ... } public WbzEx11() { p.addMouseListener(new MyMouseAdapter()); } Registrierung public static void main(String[] args) { new WbzEx11(); } } Learning By Doing // WbzEx11a.java Anonyme Klassen import java.awt.event.*; import java.awt.Color; import ch.aplu.util.*; public class WbzEx11a { private GPanel p = new GPanel(0, 500, 0, 500); public WbzEx11a() { p.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { Color c = new Color((float)Math.random(), (float)Math.random(), (float)Math.random()); Stern stern = new Stern(p, 50, c); stern.moveAt((int)p.toWindowX(evt.getX()), (int)p.toWindowY(evt.getY())); stern.showMe(); } }); } Registrierung Anonyme Klasse abgeleitet von MouseAdapter public static void main(String[] args) { new WbzEx11a(); } } Learning By Doing // WbzEx12.java Buttonevents Innere Klasse, implementiert ActionListener import java.awt.event.*; import javax.swing.*; import ch.aplu.turtle.*; public class WbzEx12 { private class ButtonActionAdapter implements ActionListener { public void actionPerformed(ActionEvent evt) { Object source = evt.getSource(); if (source == runButton) state = States.RUNNING; if (source == stopButton) State switch state = States.STOPPED; if (source == quitButton) state = States.QUITTING; } } Zustände (Aufzählungstyp) aktueller Zustand private enum States {STOPPED, RUNNING, QUITTING}; private States state = States.STOPPED; Instanzvariablen private JButton runButton = new JButton("Run"); private JButton stopButton = new JButton("Stop"); private JButton quitButton = new JButton("Quit"); public WbzEx12() Learning { Turtle t = new Turtle(); JPanel jp = t.getPlayground(); Buttonevents By Doing jp.add(runButton); jp.add(stopButton); jp.add(quitButton); jp.validate(); Buttons in der Komponente anzeigen ButtonActionAdapter adapter = new ButtonActionAdapter(); runButton.addActionListener(adapter); stopButton.addActionListener(adapter); quitButton.addActionListener(adapter); Registrierung while (state != States.QUITTING) { switch(state) { case STOPPED: Prozessor freiwillig anderen abgeben Thread.yield(); break; Event loop case RUNNING: t.forward(10).left(10); break; } } System.exit(0); } public static void main(String[] args) { new WbzEx12(); } } // WbzEx12a.java Buttonevents (J2SE 1.4) Simulation des Enum-Typs Verwendung durch Vorstellen des Interface-Bezeichners Schon viel besser als state = 2 state-Variable als "dekorierter" int Learning By Doing import java.awt.event.*; import javax.swing.*; import ch.aplu.turtle.*; public class WbzEx12a { interface State { int QUITTING = 0; int STOPPED = 1; int RUNNING = 2; } private class ButtonActionAdapter implements ActionListener { public void actionPerformed(ActionEvent evt) { Object source = evt.getSource(); if (source == runButton) state = State.RUNNING; if (source == stopButton) state = State.STOPPED; if (source == quitButton) state = State.QUITTING; } } private int state = State.STOPPED; private JButton runButton = new JButton("Run"); private JButton stopButton = new JButton("Stop"); private JButton quitButton = new JButton("Quit"); public WbzEx12a() { Learning Turtle t = new Turtle(); JPanel jp = t.getPlayground(); Buttonevents jp.add(runButton); jp.add(stopButton); jp.add(quitButton); jp.validate(); (J2SE 1.4) ButtonActionAdapter adapter = new ButtonActionAdapter(); runButton.addActionListener(adapter); stopButton.addActionListener(adapter); quitButton.addActionListener(adapter); Verwendung durch Vorstellen des Interface-Bezeichners while (state != State.QUITTING) { switch(state) { case State.STOPPED: Thread.yield(); break; case State.RUNNING: t.forward(10).left(10); break; } } System.exit(0); } public static void main(String[] args) { new WbzEx12a(); } } By Doing GUI-Muster // WbzEx13.java import java.awt.*; import javax.swing.*; import ch.aplu.util.*; Learning By Doing public class WbzEx13 extends JPanel { private int count = 0; JPanel als Grafik-Fenster public WbzEx13() { JFrame f = new JFrame("Frame Window"); f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); f.getContentPane().add(this); f.setBounds(50, 50, 550, 550); f.setVisible(true); } JFrame als umfassendes Fenster Aktion beim Klicken des Close-Buttons Füge das JPanel in das JFrame Position und Grösse des JFrames Zeige das JFrame mit Inhalt paintComponent() wird bei jedem System-Trigger aufgerufen public void paintComponent(Graphics g) { super.paintComponent(g); g.drawOval(0, 0, 500, 500); g.drawString("WBZ-Kurs \"Java im Unterricht\"", 180, 250); Graphics2D g2D = (Graphics2D)g; g2D.setStroke(new BasicStroke(8)); Line2D.Double line = new Line2D.Double(20, 300, 480, 300); g2D.draw(line); System.out.println(count++); Aufruf überschr. Methode aus JPanel Zeichnen mit dem Graphics-Context Text als Grafik Hole Graphics2D-Context Neue Linieneigenschaft (Dicke) Linie als Objekt Zeichne Grafikobjket Indikator für Aufruf von paintComponent } public static void main(String[] args) { Console.init(); new WbzEx13(); } }