Ein ActionListener ist nichts anderes als ein EventListener (... er reagiert auf das ActionEvent).
EventListener ist die allgemeine Beschreibung der Listener in Java (Swing) ... der ActionListener ist da schon ein spezifischer.
also der EventListener ist ein Interface. Er ist quasi die höchste Instanz.
Von ihm werden alle anderen Listener abgeleitet (wie z.B. der ActionListener).
Nun wollte ich in meinem Programm den Button mit ActionListener was anzeigen lassen.
Doch ich verstehe nicht, was ich alles dafür ins Programm schreiben muss damit das funktioniert?
Mit "public class BeispielListener extends JFrame" erzeugt er eine neue Klasse, die von JFrame abgeleitet wird. Das bedeutet, das Objekte die von der Klasse "BeispielListener" erzeugt werden ein JFrame sind.
Erzeugt wird das Objekt mit folgendem Sourcecode:
Java:
publicstaticvoidmain(String[] args){// Ein neues Objekt der Klasse BeispielListener wird erzeugt// und sichtbar gemachtBeispielListener bl =newBeispielListener();
bl.setVisible(true);}
Die void main Methode ist die Methode, die beim Programmstart als erstes aufgerufen wird.
Hier wird dann das Objekt "bl" anhand der Klasse "BeispielListener" erzeugt.
Da ja die Klasse "BeispielListener" von der Klasse "JFrame" abgeleitet wird (mit dem Schlüsselwort "extends"), handelt es sich beim Objekt "bl" um ein JFrame Fenster.
Mit der Methode:"public BeispielListener()" wird nun festgelegt, dass das bl Objekt, das ja ein JFrame Fenster ist 3 Buttons bekommt:
Das liegt einfach nur an der schlechten Namensgebung und der Vermengung von Dingen.
Code:
public class BeispielListener extends JFrame implements ActionListener
Die erstellte Klasse BeispielListener ist zum einen ein erweitertes JFrame. Also ist es ein Fenster und das Fenster soll halt paar Controls enthalten.
Die Klasse implementiert aber auch das Interface ActionListener. Somit ist es nicht nur ein erweitertes JFrame sondern auch noch zusätzlich ein ActionListener.
Davon darf man sich nicht irritieren lassen. Man könnte den Code aufteilen. Dann hat man auf der einen Seite nur das Fenster und in einer separaten Klasse den Listener. Zugriff auf das Fenster könnte man ja über den Konstruktor vom Listener, der eine Fenster-Referenz bekommen, übergeben.
Aber da kommen wir dann schnell in eine Design-Diskussion, bei der man dann auch überlegen müsste, in wie weit ein ableiten von JFrame überhaupt notwendig ist. Statt dessen kann man einfach ein JFrame als Instanzvariable führen und dann damit arbeiten. Es muss also nicht von JFrame abgeleitet werden.
Aber das ist dann wieder ein etwas anderes Thema.
Der ActionListerner ist eine Schnittstellenvereinbarung. Die Klasse JButton besitzt eine Methode. addActionListener( ActionListener listener );
Das bedeutet wenn Du irgend eine Klasse erstellst, die das Interface ActionListener implementiert und dann bei einem JButton die Methode addActionLister( deineKlasse ) aufrufst. Dann ruft der JButton, sofern auf ihn geklickt wird, die Methode deineKlasse.actionPerformed( ActionEvent event ) auf. Ihn dieser Methode Deiner Klasse, kannst Du dann mit Deinem Code auf das Klicken des Buttons reagieren.
Damit wird der Konstruktor der Klasse erzeugt.
Dabei muss er den gleichen Namen tragen wie die Klasse also "BeispielListener".
Wenn ich nun ein Objekt der Klasse "BeispielListener" erzeugen will, dann muss ich das mit dem Schlüsselwort "new" machen. Dabei rufe ich dann den gerade erwähnten Konstruktor der Klasse auf und erzeuge ein Objekt.
Beispiel:
Ich habe ein Programm wo ich einen Button erzeugen möchte, dann würde der Code so aussehen:
Java:
JButtonExit=newJButton();
Das heißt "JButton" ist die Klasse. "Exit" der Name des neuen Buttons-Objekt.
"new" ruft mir nun den Konstruktor der Klasse auf, um anhand der JButton Klasse ein Objekt zu erzeugen.
Ja das hört sich gut an. Maximal ein paar kleine Feinheiten im Ausdruck fallen mir jetzt auf, die aber beim Verständnis keine wirkliche Rolle spielen. So rufst Du den Konstruktor nicht auf, sondern das wird vom System beim new Operator gemacht.
Auch richtig.
Ergänzend dazu: Du kannst einen(!) Button auch 10 verschiedene ActionListener anhängen. Sobald der Button gedrückt wird werden von diesen 10 Listener der Reihe nach die "actionPerformed" Methode aufgerufen.
Achtung: Man kann ein und denselben ActionListener für unterschiedliche Buttons verwenden. Das passiert häufig in Beispielen und ist in kleinen Anwendungen sicher auch schneller und unkomplizierter.
Aber es spricht auch nichts dagegen für jeden Button einen eigenen Listener zu schreiben. Dadurch spart man sich die Abfrage welcher Button gedrückt wurde.
bin kein Experte aber damit wird abgefragt welcher button gedrückt wurde z.B.
... int whichButton = buttons.indexOf(click.getSource());//welcher Button wurde gedrückt
Ja sobald auf etwas "()" folgen kann man eigentlich davon ausgehen das hier eine Methode aufgerufen wird -> Grundlagen OOP
Wenn du genauer wissen willst wozu eine Methode gut ist was sie machen sollte und welchen Wert sie dir zurückliefert dann nutze die Java Dokumentation https://docs.oracle.com/javase/7/docs/api/java/util/EventObject.html#getSource()
Stimmt steht zwar so dort, ist aber falsch
"this" verweist immer nur auf das aktuelle Objekt. Selbst wenn du im Konstruktor "this" verwendest, verweist du auf das aktuelle Objekt was eben gerade initialisiert wird.
Mir stellt sich trotzdem die Frage, warum ich immer "this" verwende.
Ich kann doch gleich:
Java:
bl.setTitle("ActionListener Beispiel");
statt
Java:
this.setTitle("ActionListener Beispiel");
verwenden.
Hat das vielleicht den Hintergrund, dass ich mir einen haufen arbeit ersparen kann, wenn ich z.B. den Namen des Objektes von "bl" auf "el" ändere?
Wenn ich statt "this" z.B. immer "bl" verwende, dann müsste ich alle "bl" durch "el" ersetzen.
Da sich "this" aber immer auf das aktuelle Objekt bezieht, ist es egal wie das Objekt heißt.
Somit habe ich mir einen menge Schreibarbeit erspart.
privateString data;publicvoidsetData(String data){this.data = data;// data = data; würde hier nicht funktionieren}
"this" wird meist dann verwendet ein Namensproblem zwischen Parametern,lokalen Variablen und Instanzattributen zu "lösen".
Bei dem Beispiel oben hat die Klasse ein Attribut "data". "setData" soll der Instanzvariable "data" einen Wert zuweisen, sprich wird brauchen einen Parameter. Damit wir uns hier nicht einen neuen Namen ausdenken müssen nennen wir diesen ebenfalls "data".
Wenn du "data = data" schreiben würdest, dann wird dem Parameter der Parameter zugewiesen, was aber nicht dein Ziel ist.
Mit "this" greifst du nun auf das aktuelle Objekt und dessen Methoden und Attribute zu.
Mit "this" sage ich einfach, dass es sich beim "this.data" um die globale Variable des Objektes handelt, also um:
Java:
privateString data;
Ganz einfach gesagt, sorgt das "this" hier einfach für eine unterscheidung der beiden gleich genannten
"data" Variablen. Damit das Programm weiß, welches "data" zu welcher Variable gehört.
"globale Variable" ist der falsche Ausdruck, ich muss zugeben ich habe auch wenig Code dazu geschrieben.
Stell dir meinen Beispiel Code einfach innerhalb einer Klasse vor. Damit wäre "data" eine Instanzvariable.
Ansonsten stimmts, "this" wird hierbei nur zur Unterscheidung verwendet.
Evtl. liegt dein Verständnisproblem darin, dass this oft weggelassen werden kann.
Wenn Du in einer Klasse z.B. eine Instanzvariabel button hast, dann kannst Du innerhalb einer Funktion schreiben:
button.setText("aaaaa");
Aber das ist streng genommen ein
this.button.setText("aaaaa");
Das this können wir nur weglassen, wenn es in der Funktion keine lokale Variable / Parameter button gibt. Der Compiler "sucht" halt nach einem button, wenn der Ort nicht genau angegeben wurde.
Ja kannst du machen, dann fragt man sich aber wieso die 1 gibt es auch 2
Java:
publicvoidsetData(String data){this.data = data;}
Ist sauberer.
this. verwendet man größtenteils nur in Settern und im Konstruktor.
Aber man kann sich auch dafür entscheiden this. überall dort zu benutzten wo du auf Instanzattribute zugreifst. Kommt auf die Firma / Prof. / Leher / Geschmack an.
wird beim Betätigen des Buttons ein Objekt der Klasse: "ActionEvent" erzeugt.
Ich habe ja bereits geschrieben, dass der ActionListener einen Button überwacht.
Wenn der Button gedrückt wird, dann bekommt das der ActionListener mit und ruft die ActionPerformed - Methode auf. Weiters übergibt er der Methode einen Parameter, das so genannte ActionEvent.
Das ActionEvent ist doch eine Methodenvariable und keine Klasse von der ein Objekt erzeugt wird??
Nicht ganz richtig, der ActionListener ist nicht derjenige der den Buttonklick registriert. Er wird nur über den Klick informiert indem seine "actionPerformed" Methode aufgerufen wird. Als Parameter wird ein ActionEvent Objekt übergeben.
ActionEvent ist eine Klasse, von dieser Klasse können Objekte erstellt werden. An die "actionPerformed" Methode wird ein Objekt dieser Klasse übergeben.
Du kannst in der actionPerformed Methoden dann über den Parameternamen auf diese Objekt zugreifen.
Zusammen gefasst: Wenn du einem Button keinen ActionListener anhängst, dann wird passiert nichts. Der Klick auf den Button wird aber vom Java Framework trotzdem registriert. Da aber eben keine ActionListener verfügbar sind wird nichts passieren.
Der SourceCode von JButton würde dir hier etwas weiterhelfen:
addActionListener: http://grepcode.com/file/repository...ActionListener(java.awt.event.ActionListener)
Hier wird der Listener an eine Liste gehängt
Und wenn man sich nun die Links von Joose ansieht, dann sieht man die wichtigen Funktionen:
- Bei dem Hinzufügen eines ActionListeners wird das übergebene Objekt einfach mit gespeichert.
- Wenn nun das "Event ausgelöst" werden soll, dann kann man einfach alle gespeicherten ActionListener durchgehen und genau diese Funktion aufrufen.
Das ist also im Prinzip nichts anderes als bei allen objekt orientierten Entwicklungen.
Wenn Du eine Klasse Etwas hast, die die Funktion tuEtwas implementiert, dann kannst Du ja Code schreiben wie:
Code:
Etwas etwas = new Etwas(); // So es so einen Konstruktor gibt.
etwas.tuEtwas();
Also Instanz erzeugen und dann eine Funktion aufrufen.
Das ganze geht auch in Funktionen:
Code:
public void tuEtwasMitParameter(Etwas etwas) {
etwas.tuEtwas();
}
Macht nicht ganz so viel Sinn, aber vor und nach dem Aufruf könnten ja noch andere Befehle stehen. Nur um das ganze zu begreifen.
Statt aber nun auf einer Instanz direkt zu arbeiten, kann man das ja auch trennen. Ich kann innerhalb einer Klasse ja etwas haben wie:
Code:
public class Demo {
private Etwas etwas;
public void setEtwas(Etwas etwas) {
this.etwas = etwas;
}
public void machEtwas() {
etwas.tuEtwas();
}
}
Und statt die Instanz von Etwas direkt zu speichern, ist es jetzt nur noch ein kleiner Schritt, hier eine Liste von Etwas zu speichern.
Das Nächste, das evtl. verwirren könnte, wäre dann der unsichtbare Aufruf. Bei so GUIs sieht man nicht, was da im Hintergrund passiert. Man hat bei GUI Applikationen meist eine main Funktion, die einfach ein Fenster erzeugt und sich dann beendet. Und komischer Weise läuft die Applikation dann auf magische Art und Weise weiter.
Hier ist wichtig, dass die Hintergründe verstanden werden. Die Java Applikation läuft weiter, solange es Threads gibt, die nicht als Hintergrundthread (daemon) gekennzeichnet sind (bzw. exit aufgerufen wurde). Dieser Thread bearbeitet in der Regel Nachrichten, die vom System kommen (Message Loop). Das Betriebssystem ist also verantwortlich für Maus, Tastatur, Oberfläche, ... und schickt dann den Fenstern Nachrichten. Diese Nachrichten können vielfältig sein. Einfache Dinge wie "zeichne dich neu" (weil das Fenster z.B. verdeckt war) oder "Maus wurde geklickt" bis hin zu komplizierteren Dingen, die wir jetzt einfach mal ignorieren.
Wenn ein Fenster so eine Nachricht bekommt, dann wird es die Nachricht auswerten. Bei einem Mausklick kann es sein, dass es dann erst einmal schaut, auf was geklickt wurde (z.B. ein Button) und dann wird der Button aufgefordert, das Event zu bearbeiten.
Und da kommt dann das Verhalten des Buttons ins Spiel: Wenn der Button so einen Click bearbeiten soll, dann geht er einfach alle Listener durch und ruft auf diesen diese actionPerformed Funktion auf.
Das wäre dann einmal eine ganz ausführliche Erläuterung - auch wenn ich dabei einiges stark vereinfacht habe.
ActionListener: auf Deutsch Aktion Zuhörer. Also er wartet auf Aktionen bestimmter Objekte.
JButton b = new JButton( "Meine Aktion" );
b.addActionListener( myActionListener );
Also die Klasse myActionListerner wartet jetzt auf Aktionen des Buttons b.
Ein Event ist ein Ereignis, das z.B. durch einen Button (Button = Eventquelle) ausgelöst wird.
Wenn jetzt z.B. ein Button gedrückt wird, dann wird ein Event ausgelöst. Gleichzeitig wird ein "EventObjekt" der jeweiligen Klasse (z.B. ActionEvent) erzeugt.
Jedes "EventObjekt" besitzt eine Referenz zur Quelle des Auslöser, diese Quelle kann mit der Methode "getSource()" abgefragt werden.
Wichtig ist dabei zu Wissen, das jeder "EventKlasse" auch ein Listener zugeordnet ist.
Bei der "ActionEvent" -Klasse ist es eben der ActionListener.
Ist nun eine Klasse an einem bestimmten Event interessiert, so muss Sie das passende Interface für das jeweilige Event implementieren.
Der Action Listener ist ja nur ein Interface. Ein Interface ist eine spezielle Form einer Klasse.
Ein Interface besitzt nur Methoden und Konstanten, aber keine Konstruktoren.
Deshalb können von einem Interface auch keine Objekte erzeugt werden.
Der ActionListener hat nun die Aufgabe, das Event abzuhören und die "ActionPerformed()" -Methode bereit zu stellen.
Wenn jetzt ein Button gedrückt wird, dann ruft dieser nicht den ActionListener auf, sondern die Methode des ActionListeners also die "ActionPerformed()"-Methode. In der "ActionPerformed()"-Methode kann nun auf das Ereignis reagiert werden und eine bestimmte Handlung im Programm durchgeführt werden.
Wichtig ist dabei, das der Button beim ActionListener angemeldet wird und zwar mit der Methode "addActionListener".
Ja im Groben und Ganzen schon. Nur ganz am Ende hast Du es verdreht:
Wichtig ist dabei, dass der ActionListener (bzw. die Instanz, die dieses Interface implementiert) beim Button angemeldet wird und zwar mit der Methode addActionListener.
Du rufst die Methode ja auf der Button Instanz auf.
Also wenn du hast:
Button b1;
ActionListener al;
machst du:
b1.addActionListener(al);