15.7 Eine Schaltfläche (JButton)
Eine Schaltfläche (engl. button) wird verwendet, wenn der Anwender eine Aktion auslösen soll. Schaltflächen sind meistens beschriftet und stellen eine Zeichenkette dar. Unter dem AWT stellt die Klasse Button Schaltflächen dar. Erst mit der Schaltfläche JButton unter Swing lässt sich auch ein Icon mit auf die Schaltfläche bringen. Zudem ist die Hintergrundfarbe beim Standard-Look&Feel eine etwas andere, denn sie besitzt die Hintergrundfarbe des Containers.
Die Schaltfläche kann reagieren, wenn sie gedrückt wird. Dann erzeugt sie ein ActionEvent, das über einen ActionListener abgefangen wird.
Hier klicken, um das Bild zu Vergrößern
Abbildung 15.5 JButton mit einer einfachen Schaltfläche zum Schließen
Listing 15.9 JButtonDemo.java
import java.awt.event.*;
import javax.swing.*;
public class JButtonDemo
{
public static void main( String args[] )
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
JButton b = new JButton( "Ende" );
frame.getContentPane().add( b );
ActionListener al = new ActionListener() {
public void actionPerformed( ActionEvent e ) {
System.exit( 0 );
}
};
b.addActionListener( al );
frame.pack();
frame.show();
}
}
Es gibt mehrere Konstruktoren für JButton-Objekte. Die parameterlose Variante erzeugt eine Schaltfläche ohne Text. Der Text lässt sich aber mit setText() nachträglich ändern. In der Regel nutzen wir den Konstruktor, dem ein String mitgegeben wird.
class javax.swing.JButton
extends AbstractButton
implements Accessible
|
|
JButton()
Erzeugt eine neue Schaltfläche ohne Aufschrift. |
|
JButton( String text )
Erzeugt eine neue Schaltfläche mit Aufschrift. |
|
JButton( Icon icon )
Erzeugt eine neue Schaltfläche mit Icon. |
|
JButton( String text, Icon icon )
Erzeugt eine neue Schaltfläche mit Aufschrift und Icon. |
|
void setText( String text )
Ändert die Aufschrift der Schaltfläche im laufenden Betrieb. |
|
String getText()
Ändert die Aufschrift der Schaltfläche im laufenden Betrieb. |
|
void addActionListener( ActionListener l )
Fügt dem Button einen ActionListener hinzu, der die Ereignisse, die durch die Schaltfläche ausgelöst werden, abgreift. |
|
void removeActionListener( ActionListener l )
Entfernt den ActionListener wieder. Somit kann er keine weiteren Ereignisse mehr abgreifen. |
Wie wir schon gesehen haben, lässt sich der Text eines JButton-Objekts nachträglich mit setText(String) setzen und mit der entsprechenden Methode getText() auslesen. Vergleichen wir das mit den Methoden der Klasse Label. Hier heißen die Methoden zum Lesen und Ändern des Textes setLabel() und getLabel(). Dies ist für mich wieder eines der AWT-Rätsel. Warum heißt es bei einem Label-Objekt xxxText() und bei einem Button-Objekt xxxLabel()?
Hinweis Wörter mit einer starken emotionalen Bindung sollten vermieden werden. In englischen Programmen müssen Wörter wie »kill« oder »abort« umgangen werden.
|
15.7.1 Der aufmerksame ActionListener
Drücken wir die Schaltfläche, so sollte die Aktion gemeldet werden. Diese wird in Form eines ActionEvent-Objekts an den Zuhörer (ein ActionListener) gesandt. Ein ActionListener wird mit der Methode addActionListener() an die Objekte angeheftet, die Aktionen auslösen können. ActionListener ist eine Schnittstelle mit der Methode actionPerformed(). ActionListener erweitert die Schnittstelle EventListener, die von allen Listener-Interfaces implementiert werden muss.
interface java.awt.event.ActionListener
extends EventListener
|
|
abstract void actionPerformed( ActionEvent e )
Wird aufgerufen, wenn eine Aktion ausgelöst wird. |
Werfen wir noch einmal einen Blick auf die Implementierung unserer ActionListener-Klasse, die als anonyme innere Klasse realisiert ist:
ActionListener al = new ActionListener()
{
public void actionPerformed( ActionEvent e )
{
System.exit( 0 );
}
}
Wird ein ActionEvent ausgelöst, dann wird die Methode actionPerformed() aufgerufen. Wir sehen, dass als Parameter ein ActionEvent übergeben wird; die Klasse besitzt drei Methoden:
class java.awt.event.ActionEvent
extends AWTEvent
|
|
String getActionCommand()
Liefert den String, der mit dieser Aktion verbunden ist. Damit lassen sich Komponenten unterscheiden. Innerhalb der Button-Objekte handelt es sich bei dem Action-Command um die Aufschrift der Schaltfläche. Mit wenig Aufwand lässt sich so eine Schaltfläche erzeugen, die zwei Zustände beinhalten kann, beispielsweise mehr oder weniger Details. Der Behandler für das ActionEvent kann so der gleiche bleiben, kann aber über die Zeichenkette den Zustand lesen. Leider verfangen wir uns bei dieser Programmmethode schnell in landessprachenabhängiger Software. Wir werden im nächsten Abschnitt sehen, dass es dazu sinnvoll ist, den Action-Command zu setzen. |
|
int getModifiers()
Liefert den Umschaltcode für Tasten, die während des Ereignisses gedrückt waren. Die Masken sind selbstsprechend. Folgende sind als Konstanten definiert: SHIFT_MASK, CTRL_MASK, META_MASK, ALT_MASK. Diese Konstanten kommen direkt aus der Event-Klasse, so ist etwa ALT_MASK = Event.ALT_MASK. Zusätzlich gibt es noch weitere Masken: ACTION_FIRST, ACTION_LAST und ACTION_PERFORMED, die ein Synonym für ACTION_FIRST ist. |
|
String paramString()
Liefert den Erkennungsstring für das Ereignis. paramString() überschreibt die Methode von der abstrakten Klasse java.awt.AWTEvent, die dort nur den Leerstring zurückgibt, und implementiert gemäß der Vorgabe eine Methode, die einen String liefert, der den Typ der Operation und getActionCommand() vereint. Der String beginnt entweder mit »ACTION_PERFORMED« oder mit »unknown type«. |
Hier klicken, um das Bild zu Vergrößern
Den Erkennungsstring ändern
Wir haben gesehen, dass wir mit der getActionCommand()-Methode aus ActionEvent einen Kommandostring erfragen können, der im Fall der Schaltfläche mit der Beschriftung übereinstimmt. Dass allerdings dieser Text der Aufschrift entspricht, kann einschränkend und problematisch sein, zum Beispiel dann, wenn sich wie bei mehrsprachigen Anwendungen die Aufschrift ändert. Als Lösung bietet die JButton-Klasse die Methode setActionCommand() an, mit der dieser String geändert werden kann.
abstract class javax.swing.AbstractButton
extends JComponent
implements ItemSelectable, SwingConstants
|
|
void setActionCommand( String command )
Setzt einen neuen Kommandostring, wenn das Ereignis ausgeführt wird. So empfängt getActionCommand() dann command. |
15.7.2 Generic Listener für Schaltflächen-Ereignisse verwenden
Die Idee bei den Generic Listenern war, einen Ereignisauslöser mit einer Methode zu verbinden, die automatisch mittels Reflection aufgerufen wird. Damit das für die Ereignisbehandlung funktioniert, muss der Aufrufer natürlich die Methode finden und die Ereignisse zustellen können. Wir zeigen zunächst an einem Beispiel, wie an eine Schaltfläche button eine ActionListener gebunden wird. Dafür definieren wir erst eine Methode, die im Fall eines Ereignisses aufgerufen werden soll. Sie trägt nicht den typischen Methodennamen actionPerformed, nimmt aber genauso als Parameter ein ActionEvent-Objekt entgegen. Der Parameter darf nicht fehlen.
public void gedrückt( ActionEvent e ) {
System.out.println( "Button über Proxy" );
}
Als Nächstes müssen wir ein ActionListener-Objekt konstruieren und mittels der Methode addActionListener() der Schaltfläche hinzufügen. Den ActionListener konstruieren wir mit der statischen Methode create() vom GenericListener.
ActionListener buttonActionListener =
(ActionListener)(GenericListener.create(
ActionListener.class,
"actionPerformed",
this,
"gedrückt") );
button.addActionListener( buttonActionListener );
Die Parameter von create() sind:
|
Die Schnittstelle, von der das temporäre Event-Handler abgeleitet ist |
|
Die Methode der Schnittstelle, die in Wirklichkeit aufgerufen wird |
|
Das Zielobjekt (bei this sind wir das) |
|
Die Zielmethode, also die Methode, die wir selbst implementieren und die im Fall des Ereignisses aufgerufen wird |
Beispiel Wir wollen ein Programm implementieren, das zwei Schaltflächen anordnet. Die eine Schaltfläche soll über einen herkömmlichen Mechanismus die Ereignisse verwalten, und das über eine innere anonyme Klasse. Die zweite Schaltfläche soll den neuen Mechanismus mit GenericListener einsetzen. Dann soll dem Frame noch eine Methode gegeben werden, damit das Fenster geschlossen wird.
|
Interessant ist bei den Generic Listenern, dass die Auswahl einer Methode auch dann funktioniert, wenn die Schnittstelle mehrere Methoden vorschreibt. Das gilt etwa bei einem WindowListener. Wir können uns dennoch nur für eine Methode entscheiden.
WindowListener winListener =
(WindowListener)(GenericListener.create(
WindowListener.class,
"windowClosing",
this,
"fensterWirdGeschlossen") );
Obwohl der WindowListener viele Methoden vorschreibt, leiten wir lediglich bei einem windowClosing an unsere eigene Methode fensterWirdGeschlossen weiter. Und so sieht das gesamte Programm aus:
Listing 15.10 GenericListenerDemo
package genericlistener;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GenericListenerDemo extends JFrame
{
static ActionListener proxyActionListener( JComponent target,
Object implementor,
String methodname )
{
return (ActionListener)(GenericListener.create(
ActionListener.class,
"actionPerformed",
implementor,
methodname));
}
GenericListenerDemo()
{
JButton button1 = new JButton( "Normaler Listener" );
JButton button2 = new JButton( "Dynamischer Listener" );
getContentPane().setLayout( new GridLayout(2,0) );
getContentPane().add( button1 );
getContentPane().add( button2 );
// Listener wie bekannt hinzufügen
button1.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
button1Action(e);
}
} );
// Die andere Variante
button2.addActionListener( proxyActionListener( button2, this, "button2Action" ) );
// windowClosing() ist nur eine Methode von vielen
WindowListener winListener =
(WindowListener)(GenericListener.create(
WindowListener.class,
"windowClosing",
this,
"fensterWirdGeschlossen"));
addWindowListener( winListener );
pack();
show();
}
public void button1Action( ActionEvent e ) {
System.out.println( "Buttton 1" );
}
public void button2Action( ActionEvent e ) {
System.out.println( "Button 2 über Proxy" );
}
public void fensterWirdGeschlossen( WindowEvent e ) {
System.exit( 0 );
}
public static void main( String args[] )
{
new GenericListenerDemo();
}
}
15.7.3 AbstractButton
Die direkte Oberklasse für JButton ist AbstractButton, die auch für JMenuItem (somit für JCheckBox und JRadioButton) und JToggleButton Implementierungen vorgibt. Der AbstractButton ist, wie der Name schon sagt, eine abstrakte Klasse, die aus JComponent hervorgeht. Über die Oberklasse lassen sich folgende Eigenschaften für Schaltflächen steuern:
|
Ein Mnemonik; ein Zeichen, welches im Text unterstrichen dargestellt wird und schnell über Alt+Taste aufgerufen werden kann. Dies übernimmt die Methode setMnemonic (char). |
|
Automatisch eine Aktion auslösen durch doClick(). |
|
Den Zustand des Icons aufgrund des Status mit setDisabledIcon(), setDisabledSelectedIcon(), setPressedIcon(), setRolloverIcon(), setRolloverSelectedIcon() und setSelectedIcon() ändern. Alle Methoden haben ein Icon-Objekt als Parameter. |
|
Die Ausrichtung von Text und Icon in der Schaltfläche durch setVerticalAlignment() und setHorizontalAlignment() bestimmen. |
|
Die Position von Icon und Text untereinander durch setVerticalTextPosition() und setHorizontalTextPosition() bestimmen. |
Die Integration mit den Icon-Objekten liegt in der AbstractButton-Klasse. Geben wir im Konstruktor das Icon nicht an, so lässt sich dies immer noch über setIcon() nachträglich setzen und ändern. Wenn die Schaltfläche gedrückt wird, kann ein anderes Bild erscheinen. Dieses Icon setzt setPressedIcon(). Bewegen wir uns über die Schaltfläche, lässt sich auch ein anderes Icon setzen. Dazu dient die Methode setRolloverIcon(). Die Fähigkeit muss aber erst mit setRolloverEnabled(true) eingeschaltet werden. Beide Eigenschaften lassen sich auch zu einem Icon kombinieren, das erscheint, wenn die Maus über dem Bild ist und eine Selektion gemacht wird. Dazu dient setRolloverSelectedIcon(). Für ToggleButton-Objekte ist eine weitere Methode wichtig, denn ein ToggleButton hat zwei Zustände: einen selektierten und einen nicht selektierten. Auch hier können zwei Icon-Objekte zugeordnet werden, und das Icon der Selektion lässt sich mit setSelectedIcon() setzen. Ist die Schaltfläche ausgegraut, ist auch hier ein extra Icon möglich. Es wird mit setDisabledIcon() gesetzt. Dazu passt setDisabledSelectedIcon().
Hier klicken, um das Bild zu Vergrößern
Flache Schaltflächen
Neuerdings werden Schaltflächen immer flach gezeichnet, also ohne Rahmen. Auch dies können wir in Java einrichten, und es wirkt bei Symbolleisten mit Grafiken noch zeitgemäßer. Folgende Implementierung bietet sich an:
Listing 15.11 JIconButton.java
public class JIconButton extends JButton
{
public JIconButton( String file )
{
super( new ImageIcon(file) );
setContentAreaFilled( false );
setBorderPainted( false );
setFocusPainted( false );
}
}
15.7.4 JToggleButton
Ein JToggleButton (zu Deutsch Wechselknopf) hat im Gegensatz zum JButton zwei Zustände. Dies ist vergleichbar mit einem Schalter, der den Zustand »Ein« oder »Aus« annimmt. Der JButton gerät in diesen Zustand nur bei der Aktivierung, springt dann aber wieder in seinen ursprünglichen Zustand zurück. Der JToggleButton springt bei der ersten Aktivierung in einen festen Zustand und bleibt dort solange, bis er wieder aktiviert wird. Im alten AWT hat er keine Entsprechung und wird auch unter Swing selten verwendet. Er dient jedoch als Oberklasse für die Auswahlknöpfe JCheckBox und JRadioButton.
|