Indhold:
Forstå hændelser og lyttere
Abonnere på hændelser
Forudsættes af kapitel 21, Indre klasser.
Forudsætter kapitel 10, Grafiske brugergrænseflader og 11, Interfaces.
Hændelser (eng.: events) spiller en stor rolle i programmering af grafiske brugergrænseflader. Når brugeren foretager en handling, f.eks. bevæger musen, klikker, trykker en knap ned, ændrer i et tekstfelt osv., opstår der en hændelse. I Java er alle hændelser objekter (af typen Event) med metoder til at undersøge de præcise detaljer omkring hændelsen.
Hændelser udsendes af de grafiske komponenter (knapper, vinduer osv.), og hvis man vil behandle en bestemt type hændelser fra en bestemt grafisk komponent, skal man lytte efter den hændelse. Det gøres ved at registrere en lytter (eng.: listener) på hændelsestypen på den pågældende grafiske komponent.
En lytter er et objekt, der kan "abonnere" på en bestemt type hændelse. Når en lytter er registreret hos en grafisk komponent, bliver der kaldt en metode på lytter-objektet, når hændelsen indtræffer (f.eks. kaldes mouseClicked(), når der klikkes med musen).
For at sikre, at lytteren har den pågældende metode, skal lytter-objektet implementere et interface, der garanterer, at det har metoden.
F.eks.:
Appletter kan udsende hændelser af typen MouseEvent. Appletter har derfor metoden addMouseListener(MouseListener lytter), der kan bruges til at registrere lytter-objekter hos appletten. Det er kun objekter af typen MouseListener, der kan registreres som lyttere. MouseListener er et interface, så man skal lave en klasse, der implementerer MouseListener og skabe lytter-objekter ud fra dette. Når brugeren klikker med musen i appletten, udsender appletten en MouseEvent-hændelse til alle lytter-objekter, der er blevet registreret vha. addMouseListener(). Det gør appletten ved at kalde metoden mouseClicked(MouseEvent hændelse) på lytter-objekterne.
Herunder definerer vi klassen Muselytter, der implementerer MouseListener. Hver gang der sker noget med musen, skrives det ud til skærmen.
MouseListener-interfacet har bl.a. metoden mousePressed, der kaldes, når musen trykkes ned. Parameteren er et MouseEvent-objekt, der bl.a. kan fortælle, hvor musen er, og hvilken knap der blev trykket på.
import java.awt.*; import java.awt.event.*; public class Muselytter implements MouseListener { public void mousePressed(MouseEvent hændelse) // kræves af MouseListener { Point trykpunkt = hændelse.getPoint(); System.out.println("Mus trykket ned i "+trykpunkt); } public void mouseReleased(MouseEvent hændelse) // kræves af MouseListener { Point slippunkt = hændelse.getPoint(); System.out.println("Mus sluppet i "+slippunkt); } public void mouseClicked(MouseEvent hændelse) // kræves af MouseListener { System.out.println("Mus klikket i "+hændelse.getPoint()); } //-------------------------------------------------------------------- // Ubrugte hændelser (skal defineres for at implementere MouseListener) //-------------------------------------------------------------------- public void mouseEntered (MouseEvent event) {} // kræves af MouseListener public void mouseExited (MouseEvent event) {} // kræves af MouseListener }
Lad os nu lave en lille applet, der:
Opretter et muselytter-objekt.
Registrerer lytter-objektet, så det får kaldt sine metoder, når der sker noget med musen.
import java.applet.*; public class LytTilMusen extends Applet { public void init() { Muselytter lytter = new Muselytter(); this.addMouseListener(lytter); // this er objektet selv } }
Uddata fra appletten kan ses i konsolvinduet (i Netscape: Communicator/Tools/Java Console):
Mus trykket ned i java.awt.Point[x=132,y=209] Mus sluppet i java.awt.Point[x=139,y=251] Mus trykket ned i java.awt.Point[x=101,y=199] Mus sluppet i java.awt.Point[x=101,y=199] Mus klikket i java.awt.Point[x=101,y=199]
Det foregående eksempel giver ikke appletten besked om, at der er sket en hændelse. Det har man brug for, hvis man f.eks. vil tegne noget i appletten.
Herunder er et eksempel, hvor lytter-objektet (Linielytter) giver informationer om klik videre til appletten (Linietegning), sådan at en grøn linie tegnes mellem det punkt, hvor man trykkede museknappen ind, og det punkt, hvor man slap museknappen. Lytteren giver appletten besked vha. applettens to public variabler trykpunkt og slippunkt.
Lad os først kigge på appletten:
import java.awt.*; import java.awt.event.*; import java.applet.*; public class Linietegning extends Applet { public Point trykpunkt; public Point slippunkt; public void init() { Linielytter lytter = new Linielytter(); lytter.appletten = this; // initialiserer lytterens reference til appletten this.addMouseListener(lytter); } public void paint(Graphics g) { g.drawString("1:"+trykpunkt+" 2:"+slippunkt,10,10); if (trykpunkt != null && slippunkt != null) { g.setColor(Color.blue); g.drawLine(trykpunkt.x, trykpunkt.y, slippunkt.x, slippunkt.y); } } }
Linielytter er nødt til at have en reference til Linietegning-appletten:
import java.awt.*; import java.awt.event.*; import java.applet.*; public class Linielytter implements MouseListener { public Linietegning appletten; // Reference til appletten public void mousePressed(MouseEvent hændelse) // kræves af MouseListener { appletten.trykpunkt = hændelse.getPoint(); } public void mouseReleased(MouseEvent hændelse) // kræves af MouseListener { appletten.slippunkt = hændelse.getPoint(); appletten.repaint(); // Gentegn appletten lige om lidt. } //-------------------------------------------------------------------- // Ubrugte hændelser (skal defineres for at implementere interfacet) //-------------------------------------------------------------------- public void mouseClicked(MouseEvent event) {} // kræves af MouseListener public void mouseEntered (MouseEvent event) {} // kræves af MouseListener public void mouseExited (MouseEvent event) {} // kræves af MouseListener }
Med linien
appletten.repaint();
fortæller vi Linietegning-appletten, at den skal gentegne sig selv. Det forårsager kort efter et kald til dens paint()-metode.
Herunder er Linietegning igen, men nu som en applet, der selv implementerer MouseListener.
Det er linien
this.addMouseListener(this);
der registrerer applet-objektet selv som lytter.
import java.applet.*; import java.awt.*; import java.awt.event.*; public class Linietegning2 extends Applet implements MouseListener { private Point trykpunkt; private Point slippunkt; public void init() { this.addMouseListener(this); } public void paint(Graphics g) { g.drawString("1:"+trykpunkt+" 2:"+slippunkt,10,10); if (trykpunkt != null && slippunkt != null) { g.setColor(Color.blue); g.drawLine(trykpunkt.x, trykpunkt.y, slippunkt.x, slippunkt.y); } } public void mousePressed(MouseEvent hændelse) // kræves af MouseListener { trykpunkt = hændelse.getPoint(); } public void mouseReleased(MouseEvent hændelse) // kræves af MouseListener { slippunkt = hændelse.getPoint(); repaint(); } //-------------------------------------------------------------------- // Ubrugte hændelser (skal defineres for at implementere interfacet) //-------------------------------------------------------------------- public void mouseClicked(MouseEvent event) {} // kræves af MouseListener public void mouseEntered (MouseEvent event) {} // kræves af MouseListener public void mouseExited (MouseEvent event) {} // kræves af MouseListener }
Bemærk, at nu kan vores trykpunkt og slippunkt-variabler være private i stedet for public, fordi de ikke behøver at være tilgængelige udefra.
Ovenfor har vi brugt MouseListener som illustration. Her vil vi give eksempler på brug af de andre typer lyttere (beskrevet i appendiks senere i kapitlet).
Med MouseMotionListener får man adgang til hændelserne mouseMoved og mouseDragged. Det kan bruges til at tegne grafiske figurer ved at hive musen hen over skærmen.
Her er en applet til at tegne kruseduller. Vi husker punktet, når musen trykkes ned (mousePressed()), og tegner en linie fra forrige punkt til musen, når den trækkes med nedtrykket knap (mouseDragged()).
Tegningen af grafikken sker direkte i håndteringen af hændelsen.
import java.applet.*; import java.awt.*; import java.awt.event.*; public class Kruseduller extends Applet implements MouseListener, MouseMotionListener { public void init() { this.addMouseListener(this); this.addMouseMotionListener(this); } Point punkt; public void mousePressed(MouseEvent hændelse) // kræves af MouseListener { punkt = hændelse.getPoint(); } public void mouseDragged(MouseEvent hændelse) // kræves af MouseMotionListener { Point gammeltPunkt = punkt; punkt = hændelse.getPoint(); Graphics g = getGraphics(); g.drawLine(gammeltPunkt.x, gammeltPunkt.y, punkt.x, punkt.y); } public void mouseReleased (MouseEvent hændelse){} // kræves af MouseListener public void mouseClicked (MouseEvent event) {} // kræves af MouseListener public void mouseEntered (MouseEvent event) {} // kræves af MouseListener public void mouseExited (MouseEvent event) {} // kræves af MouseListener public void mouseMoved (MouseEvent hændelse) {}// kræves af MouseMotionListener }
Da vi ikke husker de gamle punkter, kan vi ikke gentegne krusedullen, når systemet kalder paint().
Det vigtigste interface til programmering af grafiske brugergrænseflader er ActionListener med metoden actionPerformed(). Den bruges bl.a. til at lytte til, om knapper bliver trykket på. Her er et eksempel, hvor den tekst, der er valgt med musen i et tekstområde, bliver kopieret til det andet tekstområde, når man trykker på knappen:
import java.applet.*; import java.awt.*; import java.awt.event.*; public class LytTilKnap extends Applet implements ActionListener { private TextArea t1, t2; private Button kopierKnap; public void init() { String s = "Her er en tekst.\nMarkér noget af den og tryk Kopier..."; t1 = new TextArea(s, 5,20); add(t1); kopierKnap = new Button("Kopiér>>"); kopierKnap.addActionListener(this); add(kopierKnap); t2 = new TextArea( 5,20); t2.setEditable(false); add(t2); } public void actionPerformed(ActionEvent e) // kræves af ActionListener { t2.setText(t1.getSelectedText() ); } }
Læg mærke til, at vi registrerer lytteren (som er applet-objektet selv) hos knappen.
Det følgende er en oversigt over lytter-interfaces og deres hændelser.
Hændelsen ActionEvent sendes af den pågældende komponent, når brugeren klikker på en knap, trykker retur i et tekstfelt, vælger noget i et afkrydsningsfelt, radioknap, menu eller lignende.
public interface ActionListener { public void actionPerformed(ActionEvent e); }
Sendes af alle grafiske komponenter (Button, TextField, Checkbox osv., og Frame, Applet, Panel,...), når de hhv. ændrer størrelse, position, bliver synlige eller usynlige.
public interface ComponentListener { public void componentResized(ComponentEvent e); public void componentMoved(ComponentEvent e); public void componentShown(ComponentEvent e); public void componentHidden(ComponentEvent e); }
Sendes af komponenter, når de får fokus (dvs. hvis brugere trykker på en tast, vil det påvirke netop denne komponent). Kun en komponent har fokus ad gangen1.
public interface FocusListener { public void focusGained(FocusEvent e); public void focusLost(FocusEvent e); }
Sendes af afkrydsningsfelter og radioknapper, når en mulighed bliver krydset af eller fravalgt.
public interface ItemListener { void itemStateChanged(ItemEvent e); }
Sendes af komponenten, der har fokus. keyPressed() kaldes, når en tast bliver trykket ned (bemærk, at der godt kan være flere taster trykket ned samtidig, f.eks. Ctrl og C) og keyReleased(), når den bliver sluppet. Er man mere overordnet interesseret i, hvad brugeren taster ind, bør man benytte keyTyped(), der svarer til, at brugeren har trykket en tast ned og sluppet den igen.
public interface KeyListener { public void keyTyped(KeyEvent e); public void keyPressed(KeyEvent e); public void keyReleased(KeyEvent e); }
Kan sendes af alle grafiske komponenter. mousePressed() kaldes, når en museknap bliver trykket ned, og mouseReleased(), når den bliver sluppet igen. Er man mere overordnet interesseret i at vide, om brugeren har klikket et sted (trykket ned og sluppet på det samme sted), bør man benytte mouseClicked(). mouseEntered() og mouseExited() sendes, når musen går ind over hhv. væk fra komponenten.
public interface MouseListener { public void mousePressed(MouseEvent e); public void mouseReleased(MouseEvent e); public void mouseClicked(MouseEvent e); public void mouseEntered(MouseEvent e); public void mouseExited(MouseEvent e); }
Kan sendes af alle grafiske komponenter. mouseDragged() kaldes, når en museknap er trykket ned og hives (bevæges, mens museknappen forbliver trykket ned). mouseMoved() svarer til, at musen flyttes (uden nogle knapper trykket ned).
public interface MouseMotionListener { public void mouseDragged(MouseEvent e); public void mouseMoved(MouseEvent e); }
Sendes af tekstfelter (TextField og TextArea), når brugeren ændrer teksten.
public interface TextListener { public void textValueChanged(TextEvent e); }
Sendes af vinduer (Frame og Dialog), når de åbnes, forsøges lukket, lukkes, minimeres, gendannes, får fokus og mister fokus.
public interface WindowListener { public void windowOpened(WindowEvent e); public void windowClosing(WindowEvent e); public void windowClosed(WindowEvent e); public void windowIconified(WindowEvent e); public void windowDeiconified(WindowEvent e); public void windowActivated(WindowEvent e); public void windowDeactivated(WindowEvent e); }
Dette afsnit findes i den trykte bog
1Man kan anmode om fokus på en komponent ved at kalde requestFocus() på den.