1 / 20

Ereignisbehandlung mit Java

Ereignisbehandlung mit Java. Computer gestern und heute. Pionierzeit: Auf einem Computer läuft genau ein Programm und beansprucht sämtliche Rechenzeit für sich. Wenn das Programm beendet ist, gibt es ein Ergebnis aus. Das Programmiermodell ist die sequenzielle Programmierung.

biana
Download Presentation

Ereignisbehandlung mit Java

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Ereignisbehandlung mit Java Michael Weiss

  2. Computer gestern und heute • Pionierzeit: • Auf einem Computer läuft genau ein Programm und beansprucht sämtliche Rechenzeit für sich. • Wenn das Programm beendet ist, gibt es ein Ergebnis aus. • Das Programmiermodell ist die sequenzielle Programmierung. • Moderner Computer: • Auf einem Computer laufen viele Programme quasi gleichzeitig. Die meiste Zeit haben diese Programme jedoch nichts zu tun. • Ein Programm, das etwas tun soll, bekommt ein Signal. Dieses geht von der Hardware (z.B. Tastatur, Maus, Timer, Netzwerkkarte) aus und kommt über das Betriebssystem zum Programm. • Das Programmiermodell ist die ereignisgesteuerte Programmierung. Michael Weiss

  3. Ereignissteuerung in Java • Ereignisse werden ausgelöst: • durch Hardware (z.B. Mausklicks, Tastendruck) • durch das Betriebssystem (z.B.: es ist Zeit, ein Fenster neu zu zeichnen) • durch Timer • durch GUI-Elemente (z.B. Button angeklickt, Slider verschoben, Fenster vergrössert usw.) • Um Ereignisse zu behandeln, muss man Java mitteilen • dass man auf ein Ereignis reagieren möchte • wie man auf ein Ereignis reagieren möchte Michael Weiss

  4. Ich möchte auf ein Button-Ereignis reagieren! Bsp. Pause-Button im Uhr-Projekt: hatPauseJButton.addActionListener(hatEreignisVerarbeiter); Hierbei ist hatEreignisVerarbeiterer ein Objekt einer von der Klasse ActionListenerabgeleiteten, selbst geschriebenen Klasse namens EreignisVerarbeiter. Die Klasse ActionListenerbesitzt lediglich eine einzige Methode, die zudem abstrakt ist: abstractvoidactionPerformed(ActionEvent e); Michael Weiss

  5. Einschub I: Interfaces • Klassen, welche lediglich abstrakte Methoden und Konstanten besitzen, werden in Java Interfaces genannt. • Klassen, welche die Konstanten eines Interfaces übernehmen und deren abstrakte Methoden mit konkreten Methoden überschreiben, erweitern das Interface nicht, sondern implementieren es. • Während eine Klasse nur eine einzige Überklasse erweitern kann, kann sie beliebig viele Interfaces implementieren. • Beispiel ActionListener: publicinterfaceActionListener { voidActionPerformed(ActionEventevt); } (Hinweis: Dieses Interface existiert bereits. Sie müssen es aber noch implementieren.) Michael Weiss

  6. ActionListener implementieren classEreignisVerarbeiterimplementsActionListener{ publicvoidactionPerformed(ActionEventevt){ // hier der Code, was geschehen soll, // wenn ActionPerformed() aufgerufen wurde } } • Das Objekt der Klasse ActionEvent, auf das mit evt verwiesen wird, enthält u.a. Informationen darüber, welches Objekt das Ereignis ausgelöst hat und wann das Ereignis ausgelöst wurde. • Es ist daher möglich, dass das selbe EreignisVerarbeiter-Objekt verschiedene Ereignisse bearbeitet: publicvoidactionPerformed(ActionEventevt){ Object source =evt.getSource(); if(source ==hatPauseJButton){ // Hier Code um Uhr anzuhalten }elseif(source==hatStellenJButton){ // Hier Code um Uhr zu stellen } } Michael Weiss

  7. Einschub II: Innere Klassen • Der Code von actionPerformed() benötigt Zugriff auf die privaten Objekte der Klasse Uhr. • Ausserhalb der Klasse Uhr wird die Klasse EreignisVerarbeiter nicht benötigt. • Wir nutzen daher die Möglichkeit von Java, Klassen zu verschachteln und definieren EreignisVerarbeiter als private innere Klasse von Uhr: publicclass Uhr { // hier Variablen, Konstruktoren und Methoden der Klasse Uhr // innere Klasse privateclassEreignisVerarbeiterimplementsActionListener{ publicvoidactionPerformed(ActionEventevt){ // Code von actionPerformed() } }// Ende der inneren Klasse }// Ende der äusseren Klasse Michael Weiss

  8. Es gibt nicht nur Button-Events • Die Methode addActionListener() kann ausser beim JButton u.a. noch für folgende Ereignisauslöser benutzt werden: • JCheckBox • JCheckBoxMenuItem • JRadioButton • JRadioButtonMenuItem • JToggleButton • Timer (aus javax.swing) • Die meisten GUI-Elemente können jedoch verschiedene Ereignisse behandeln und benutzen daher speziell für sie zugeschnittene Listener. Für jeden Typ Listener muss man eine eigene innere private Klasse schreiben. Michael Weiss

  9. Beispiel: KeyListener Um Tastatureingaben in einem Fenster zu verarbeiten, wird ein KeyListener benutzt. Das folgende einfache Programm schreibt den Namen der gedrückten Taste auf den Bildschirm. Michael Weiss

  10. importjavax.swing.*;importjava.awt.*;importjava.awt.event.*;importjava.awt.geom.*;importjavax.swing.*;importjava.awt.*;importjava.awt.event.*;importjava.awt.geom.*; importjava.awt.font.*; publicclassTastatur { JFramehatJFrame; ZeichenJPanelhatZeichenJPanel; String zKeyText=" "; MyKeyListenerhatMyKeyListener; publicTastatur() { hatJFrame=newJFrame("Tastaturcode"); hatJFrame.setBounds(100,100,400,200); hatZeichenJPanel=newZeichenJPanel(); hatJFrame.add(hatZeichenJPanel); hatMyKeyListener=newMyKeyListener(); hatJFrame.addKeyListener(hatMyKeyListener); hatJFrame.setResizable(false); hatJFrame.setVisible(true); } privateclassZeichenJPanelextendsJPanel{ Rectangle2D.Float r; Font f =new Font("Arial",Font.PLAIN,30); publicvoidpaintComponent(Graphics g){ super.paintComponent(g); g.setColor(Color.black); g.setFont(f); r =(Rectangle2D.Float)((newTextLayout(zKeyText,f, // Platzbedarf des Textes ermitteln ((Graphics2D)g).getFontRenderContext())).getBounds()); g.drawString(zKeyText,(int)((this.getWidth()-r.getWidth())/2), // Text in der Fenstermitte (int)((this.getHeight()+r.getHeight())/2)); // platzieren } } Michael Weiss

  11. privateclassMyKeyListenerimplementsKeyListener{ publicvoidkeyPressed(KeyEventevt){ zKeyText=evt.getKeyText(evt.getKeyCode()); hatZeichenJPanel.repaint(); } publicvoidkeyReleased(KeyEventevt){} publicvoidkeyTyped(KeyEventevt){}// würde benötigt, um z.B. die Eingabe eines ê oder @ // zu melden (beide brauchen Tastenkombinationen) }// Ende der inneren Klasse MyKeyListener staticpublicvoid main(String[]args) { new Tastatur(); } } • Obwohl die Methoden keyReleased()und keyTyped() gar nicht gebraucht werden, müssen sie implementiert werden, weil MyKeyListener das Interface KeyListener implementiert und dieses Interface entsprechende abstrakte Methoden aufweist. • Manche Listener haben sehr viele Methoden. Damit man nicht immer alle Methoden implementieren muss, die man gar nicht braucht, stellt Java für die Listener sogenannte Adapterklassen zur Verfügung, in denen alle abstrakten Interface-Methoden als leere Methoden implementiert sind. Z.B. gibt es eine Klasse KeyAdapter: importjava.awt.event.*; publicclassKeyAdapterimplementsKeyListener{ publicvoidkeyPressed(KeyEventevt){} publicvoidkeyReleased(KeyEventevt){} publicvoidkeyTyped(KeyEventevt){} } (Diese Klasse müssen Sie nicht mehr schreiben!) Michael Weiss

  12. Wird die Adapterklasse benutzt, sieht MyKeyListener so aus: privateclassMyKeyListenerextendsKeyAdapter{ publicvoidkeyPressed(KeyEventevt){ zKeyText=evt.getKeyText(evt.getKeyCode()); hatZeichenJPanel.repaint(); } }// Ende der inneren Klasse MyKeyListener • In einem komplexen Anwendung besteht die Gefahr, dass durch die Verteilung der Ereignisbehandlung auf viele Listener-Methoden die Übersicht verloren geht. • Es ist daher vorteilhaft, die gesamte Ereignisbehandlung in einer einzigen Methode durchzuführen, welche von allen Listener-Methoden aufgerufen wird. • Das Beispiel auf den folgenden Seiten erweitert das Tastatur-Beispiel. Michael Weiss

  13. importjavax.swing.*;importjava.awt.*;importjava.awt.event.*; importjava.awt.geom.*;importjava.awt.font.*;importjava.util.EventObject; publicclassTastaturUndMaus { privateJFramehatJFrame; privateZeichenJPanelhatZeichenJPanel; privateJPanelhatSouthJPanel; privateJButtonhatBeendenJButton; privateJCheckBoxhatKursivJCheckBox; private String zKeyText=" "; privateMyKeyListenerhatMyKeyListener; privateMyMouseListenerhatMyMouseListener; privateMyActionListenerhatMyActionListener; privatefinalstaticint KEY_PRESSED =0, MOUSE_CLICKED =1, MOUSE_ENTERED =2, MOUSE_EXITED =3,MOUSE_PRESSED =4, MOUSE_RELEASED =5, ACTION_EVENT =6; publicTastaturUndMaus() { hatJFrame=newJFrame("Tastatur und Maus"); hatJFrame.setBounds(100,100,400,300); hatJFrame.setLayout(newBorderLayout()); hatZeichenJPanel=newZeichenJPanel(); hatZeichenJPanel.setBackground(Color.WHITE); hatJFrame.add(hatZeichenJPanel,BorderLayout.CENTER); hatSouthJPanel=newJPanel(); hatJFrame.add(hatSouthJPanel,BorderLayout.SOUTH); hatSouthJPanel.setLayout(newFlowLayout(FlowLayout.CENTER,10,10)); // Layout, um GUI-Ele- // mentein "natürlicher" Grösseungezwungen gemeinsam in einem Panel zu platzieren hatKursivJCheckBox=newJCheckBox("Kursiv"); hatKursivJCheckBox.setFocusable(false); hatSouthJPanel.add(hatKursivJCheckBox); hatBeendenJButton=newJButton("Beenden"); hatBeendenJButton.setFocusable(false); hatSouthJPanel.add(hatBeendenJButton); hatJFrame.setResizable(false); hatJFrame.setVisible(true); Michael Weiss

  14. hatMyActionListener=newMyActionListener(); hatMyKeyListener=newMyKeyListener(); hatMyMouseListener=newMyMouseListener(); hatKursivJCheckBox.addActionListener(hatMyActionListener); hatBeendenJButton.addActionListener(hatMyActionListener); hatZeichenJPanel.addMouseListener(hatMyMouseListener); hatZeichenJPanel.addKeyListener(hatMyKeyListener); hatZeichenJPanel.requestFocusInWindow(); } privateclassMyKeyListenerextendsKeyAdapter{ publicvoidkeyPressed(KeyEventevt){ verarbeiteEreignis(evt, KEY_PRESSED); } } privateclassMyMouseListenerimplementsMouseListener{ publicvoidmouseClicked(MouseEventevt){ verarbeiteEreignis(evt, MOUSE_CLICKED); } publicvoidmouseEntered(MouseEventevt){ verarbeiteEreignis(evt, MOUSE_ENTERED); } publicvoidmouseExited(MouseEventevt){ verarbeiteEreignis(evt, MOUSE_EXITED); } publicvoidmousePressed(MouseEventevt){ verarbeiteEreignis(evt, MOUSE_PRESSED); } publicvoidmouseReleased(MouseEventevt){ verarbeiteEreignis(evt, MOUSE_RELEASED); } } privateclassMyActionListenerimplementsActionListener{ publicvoidactionPerformed(ActionEventevt){ verarbeiteEreignis(evt, ACTION_EVENT); } } Michael Weiss

  15. privatevoidverarbeiteEreignis(EventObjectevt,int type){ Object obj=evt.getSource(); if(evtinstanceofKeyEvent){ KeyEventke=(KeyEvent)evt; zKeyText=ke.getKeyText(ke.getKeyCode()); }elseif(evtinstanceofMouseEvent){ switch(type){ case MOUSE_CLICKED: zKeyText="Mouse clicked"; break; case MOUSE_ENTERED: zKeyText="Mouse entered"; break; case MOUSE_EXITED: zKeyText="Mouse exited"; break; case MOUSE_PRESSED: zKeyText="Mouse pressed"; break; case MOUSE_RELEASED: zKeyText="Mouse released"; break; default: zKeyText="ERROR!"; break; } }elseif(evtinstanceofActionEvent){ if(obj==hatKursivJCheckBox){ hatZeichenJPanel.setItalicFont(hatKursivJCheckBox.isSelected()); }elseif(obj==hatBeendenJButton){ System.exit(0); } } hatZeichenJPanel.repaint(); } Mit dem Schlüsselwort instanceoflässt sich testen, ob ein Objekt zu einer bestimmten Klasse gehört, ob also z.B. evt ein Objekt der Klasse KeyEvent ist. Michael Weiss

  16. privateclassZeichenJPanelextendsJPanel{ Rectangle2D.Float r; Font fp=new Font("Arial",Font.PLAIN,30); Font fi =new Font("Arial",Font.ITALIC,30); Font f =fp; publicvoidsetItalicFont(booleanyesorno){ f =yesorno? fi :fp; // Falls yesorno == true ist, setze f = fi, sonst setze f = fp. } publicvoidpaintComponent(Graphics g){ super.paintComponent(g); g.setColor(Color.black); g.setFont(f); r =(Rectangle2D.Float)((newTextLayout(zKeyText,f, ((Graphics2D)g).getFontRenderContext())).getBounds()); g.drawString(zKeyText,(int)((this.getWidth()-r.getWidth())/2), (int)((this.getHeight()+r.getHeight())/2)); } } staticpublicvoid main(String[]args) { try{// 5 Zeilen, damit sich das Programm ins OS integriert UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }catch(Exception e){ System.err.println("no system look and feel available"); }; newTastaturUndMaus(); } } Michael Weiss

  17. Timer-Events • Der Timerist ein Objekt, welches die Fähigkeit besitzt, alle t Millisekunden die Methode actionPerformed() einer selbst geschriebenen Klasse (z.B. MyActionListener) aufzurufen, welche das Interface ActionListener implementiert. • Im Gegensatz zum JButton übergibt man den ActionListener nicht mit einer Methode addActionListener, sondern bereits im Konstruktor. • Mit start() und stop() kann der Timer ein- und ausgeschaltet werden, mit setDelay(int t) kann die Anzahl Millisekunden verändert werden, nach denen der Timer jeweils die Methode actionPerformed() aufruft. • Im folgenden Beispiel zählt der Timer Sekunden und gibt sie auf dem Bildschirm aus. Michael Weiss

  18. importjavax.swing.*; importjava.awt.*; importjava.awt.event.*; importjava.awt.geom.*;importjava.awt.font.*;importjava.util.EventObject; publicclassZaehler { privateJFramehatJFrame; privateZeichenJPanelhatZeichenJPanel; privateJPanelhatSouthJPanel; privateJButtonhatBeendenJButton; private String zText="0"; privateMyActionListenerhatMyActionListener; private Timer hatTimer; privateint t =0; publicZaehler() { hatJFrame=newJFrame("Zähler"); hatJFrame.setBounds(100,100,400,300); hatJFrame.setLayout(newBorderLayout()); hatZeichenJPanel=newZeichenJPanel(); hatJFrame.add(hatZeichenJPanel,BorderLayout.CENTER); hatSouthJPanel=newJPanel(); hatJFrame.add(hatSouthJPanel,BorderLayout.SOUTH); hatSouthJPanel.setLayout(newFlowLayout(FlowLayout.CENTER,10,10)); hatBeendenJButton=newJButton("Beenden"); hatBeendenJButton.setFocusable(false); hatSouthJPanel.add(hatBeendenJButton); hatJFrame.setResizable(false); hatJFrame.setVisible(true); hatMyActionListener=newMyActionListener(); hatTimer=new Timer(1000,hatMyActionListener); hatTimer.start(); hatBeendenJButton.addActionListener(hatMyActionListener); } Michael Weiss

  19. privateclassMyActionListenerimplementsActionListener{ publicvoidactionPerformed(ActionEventevt){ verarbeiteEreignis(evt); } } privatevoidverarbeiteEreignis(EventObjectevt){ Object obj=evt.getSource(); if(obj==hatTimer){ t++; zText= t+"";// einfachste Methode, eine Zahl in einen String zu verwandeln hatZeichenJPanel.repaint(); }elseif(obj==hatBeendenJButton){ System.exit(0); } } privateclassZeichenJPanelextendsJPanel{ Rectangle2D.Float r; Font f =new Font("Arial",Font.PLAIN,30); publicvoidpaintComponent(Graphics g){ super.paintComponent(g); g.setColor(Color.black); g.setFont(f); r =(Rectangle2D.Float)((newTextLayout(zText,f, ((Graphics2D)g).getFontRenderContext())).getBounds()); g.drawString(zText,(int)((this.getWidth()-r.getWidth())/2), (int)((this.getHeight()+r.getHeight())/2)); } } Michael Weiss

  20. staticpublicvoid main(String[]args) { try{// 5 Zeilen, damit sich das Programm ins OS integriert UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }catch(Exception e){ System.err.println("no system look and feel available"); }; newZaehler(); } } In diesem Fall erzeugen alle Ereigniserzeuger (Timer und JButton) ActionEvents, weswegen die Methode verarbeiteEreignis() auch ohne Verlust an Übersichtlichkeit in actionPerformed() hätte integriert werden können. Michael Weiss

More Related