Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Java ist auch eine Insel von Christian Ullenboom
Buch: Java ist auch eine Insel (Galileo Computing)
gp Kapitel 15 Komponenten, Container und Ereignisse
gp 15.1 Es tut sich was - Ereignisse beim AWT
gp 15.1.1 Was ist ein Ereignis?
gp 15.1.2 Die Klasse AWTEvent
gp 15.1.3 Events auf verschiedenen Ebenen
gp 15.1.4 Ereignisquellen, -senken und Horcher (Listener)
gp 15.1.5 Listener implementieren
gp 15.1.6 Listener bei Ereignisauslöser anmelden
gp 15.2 Varianten, das Fenster zu schließen
gp 15.2.1 Eine Klasse implementiert die Schnittstelle WindowListener
gp 15.2.2 Adapterklassen nutzen
gp 15.2.3 Innere Mitgliedsklassen und innere anonyme Klassen
gp 15.2.4 Generic Listener
gp 15.3 Komponenten im AWT und in Swing
gp 15.3.1 Peer-Klassen und Lightweight-Komponenten
gp 15.3.2 Die Basis aller Komponenten: Component und JComponent
gp 15.3.3 Proportionales Vergrößern eines Fensters
gp 15.3.4 Dynamisches Layout während einer Größenänderung
gp 15.3.5 Hinzufügen von Komponenten
gp 15.4 Das Swing-Fenster JFrame
gp 15.4.1 Kinder auf einem Swing-Fenster
gp 15.4.2 Schließen eines Swing-Fensters
gp 15.5 Ein Informationstext über die Klasse JLabel
gp 15.5.1 Mehrzeiliger Text
gp 15.6 Die Klasse ImageIcon
gp 15.6.1 Die Schnittstelle Icon
gp 15.6.2 Was Icon und Image verbindet
gp 15.7 Eine Schaltfläche (JButton)
gp 15.7.1 Der aufmerksame ActionListener
gp 15.7.2 Generic Listener für Schaltflächen-Ereignisse verwenden
gp 15.7.3 AbstractButton
gp 15.7.4 JToggleButton
gp 15.8 Tooltips
gp 15.9 Horizontale und vertikale Schieberegler
gp 15.9.1 Der AdjustmentListener, der auf Änderungen hört
gp 15.10 JSlider
gp 15.11 Ein Auswahlmenü - Choice, JComboBox
gp 15.11.1 ItemListener
gp 15.11.2 Zuordnung einer Taste mit einem Eintrag
gp 15.12 Eines aus vielen - Kontrollfelder (JCheckBox)
gp 15.12.1 Ereignisse über ItemListener
gp 15.13 Kontrollfeldgruppen, Optionsfelder und JRadioButton
gp 15.14 Der Fortschrittsbalken JProgressBar
gp 15.15 Rahmen (Borders)
gp 15.16 Symbolleisten alias Toolbars
gp 15.17 Menüs
gp 15.17.1 Die Menüleisten und die Einträge
gp 15.17.2 Menüeinträge definieren
gp 15.17.3 Mnemonics und Shortcuts (Accelerator)
gp 15.17.4 Beispiel für ein Programm mit Menüleisten
gp 15.18 Popup-Menüs
gp 15.19 Alles Auslegungssache: die Layoutmanager
gp 15.19.1 Null-Layout
gp 15.19.2 FlowLayout
gp 15.19.3 BorderLayout
gp 15.19.4 GridLayout
gp 15.19.5 Der GridBagLayout-Manager
gp 15.19.6 Weitere Layoutmanager
gp 15.20 Der Inhalt einer Zeichenfläche: JPanel
gp 15.21 Das Konzept des Model-View-Controllers
gp 15.22 List-Boxen
gp 15.23 JSpinner
gp 15.24 Texteingabefelder
gp 15.24.1 Text in einer Eingabezeile
gp 15.24.2 Die Oberklasse der JText-Komponenten: JTextComponent
gp 15.24.3 JPasswordField
gp 15.24.4 Validierende Eingabefelder
gp 15.24.5 Mehrzeilige Textfelder
gp 15.24.6 Die Editor-Klasse JEditorPane
gp 15.25 Bäume mit JTree-Objekten
gp 15.25.1 Selektionen bemerken
gp 15.26 Tabellen mit JTable
gp 15.26.1 Ein eigenes Modell
gp 15.26.2 AbstractTableModel
gp 15.26.3 DefaultTableModel
gp 15.26.4 Ein eigener Renderer für Tabellen
gp 15.26.5 Spalteninformationen
gp 15.26.6 Tabellenkopf von Swing-Tabellen
gp 15.26.7 Selektionen einer Tabelle
gp 15.27 JRootPane und JLayeredPane
gp 15.28 Dialoge
gp 15.28.1 Der Farbauswahldialog JColorChooser
gp 15.28.2 Der Dateiauswahldialog
gp 15.29 Das Java-Look&Feel
gp 15.30 Swing-Beschriftungen einer anderen Sprache geben
gp 15.31 Die Zwischenablage (Clipboard)
gp 15.32 Undo durchführen
gp 15.33 Ereignisverarbeitung auf unterster Ebene
gp 15.34 AWT, Swing und die Threads
gp 15.34.1 Warum Swing nicht Thread-sicher ist
gp 15.34.2 Swing-Elemente bedienen mit invokeLater() und invokeAndWait()
gp 15.35 Selbst definierte Cursor
gp 15.35.1 Flackern des Mauszeigers bei Animationen vermeiden
gp 15.36 Mausrad-Unterstützung
gp 15.37 Benutzerinteraktionen automatisieren
gp 15.37.1 Automatisch in die Tasten hauen
gp 15.37.2 Mausoperationen
gp 15.37.3 Methoden zur Zeitsteuerung
gp 15.37.4 Screenshots
gp 15.37.5 Funktionsweise und Beschränkungen


Galileo Computing

15.7 Eine Schaltfläche (JButton)downtop

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.

Abbildung
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

gp JButton()
Erzeugt eine neue Schaltfläche ohne Aufschrift.
gp JButton( String text )
Erzeugt eine neue Schaltfläche mit Aufschrift.
gp JButton( Icon icon )
Erzeugt eine neue Schaltfläche mit Icon.
gp JButton( String text, Icon icon )
Erzeugt eine neue Schaltfläche mit Aufschrift und Icon.
gp void setText( String text )
Ändert die Aufschrift der Schaltfläche im laufenden Betrieb.
gp String getText()
Ändert die Aufschrift der Schaltfläche im laufenden Betrieb.
gp void addActionListener( ActionListener l )
Fügt dem Button einen ActionListener hinzu, der die Ereignisse, die durch die Schaltfläche ausgelöst werden, abgreift.
gp 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.


Galileo Computing

15.7.1 Der aufmerksame ActionListenerdowntop

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

gp 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

gp 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.
gp 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.
gp 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«.

Abbildung
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

gp void setActionCommand( String command )
Setzt einen neuen Kommandostring, wenn das Ereignis ausgeführt wird. So empfängt getActionCommand() dann command.

Galileo Computing

15.7.2 Generic Listener für Schaltflächen-Ereignisse verwendendowntop

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:

gp Die Schnittstelle, von der das temporäre Event-Handler abgeleitet ist
gp Die Methode der Schnittstelle, die in Wirklichkeit aufgerufen wird
gp Das Zielobjekt (bei this sind wir das)
gp 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();
  }
}

Galileo Computing

15.7.3 AbstractButtondowntop

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:

gp Ein Mnemonik; ein Zeichen, welches im Text unterstrichen dargestellt wird und schnell über Alt+Taste aufgerufen werden kann. Dies übernimmt die Methode setMnemonic (char).
gp Automatisch eine Aktion auslösen durch doClick().
gp Den Zustand des Icons aufgrund des Status mit setDisabledIcon(), setDisabledSelectedIcon(), setPressedIcon(), setRolloverIcon(), setRolloverSelectedIcon() und setSelectedIcon() ändern. Alle Methoden haben ein Icon-Objekt als Parameter.
gp Die Ausrichtung von Text und Icon in der Schaltfläche durch setVerticalAlignment() und setHorizontalAlignment() bestimmen.
gp 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().

Abbildung
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 );
  }
}

Galileo Computing

15.7.4 JToggleButtontoptop

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.





Copyright (c) Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de