Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage
<< | < | > | >> | API | Kapitel 30 - Menüs

## 30.4 Menüeinträge

- 30.4 Menüeinträge
  - 30.4.1 Einfache Menüeinträge
  - 30.4.2 CheckboxMenuItem
  - 30.4.3 Beschleunigertasten
  - 30.4.4 Untermenüs

### 30.4.1 Einfache Menüeinträge

Die Menüeinträge sind die elementaren Bestandteile eines Menüs. Sie besitzen einen Text, mit dem sie dem Anwender die dahinterstehende Funktion anzeigen. Wenn der zugehörige Menüpunkt aufgerufen wird, sendet das Programm eine Nachricht an das zugehörige Fenster, die dann zum Aufruf der entsprechenden Methode führt.

Menüeinträge werden in Java mit der Klasse `MenuItem` erzeugt. Ihr Konstruktor erwartet als Parameter einen `String`, der den Namen des Menüeintrags angibt:

    public MenuItem(String label)
| java.awt.MenuItem

Auch nach der Konstruktion eines Menüeintrags ist ein Zugriff auf seinen Namen möglich. Mit der Methode `getLabel` kann der Name des Menüeintrags abgefragt und mit `setLabel` sogar verändert werden:

    public String getLabel()

    public void setLabel(String label)
| java.awt.MenuItem

Neben einem Namen besitzt ein Menüeintrag eine interne Zustandsvariable, die anzeigt, ob er aktiv ist oder nicht. Nur ein aktiver Eintrag kann vom Anwender ausgewählt werden und so eine Nachricht auslösen. Ein inaktiver Eintrag dagegen wird im Menü grau dargestellt, kann vom Anwender nicht mehr ausgewählt werden und daher auch keine Nachricht mehr auslösen.

Nach dem Aufruf des Konstruktors ist ein Menüeintrag zunächst aktiviert. Er kann durch Aufruf von `setEnabled(false)` deaktiviert und mit `setEnabled(true)` aktiviert werden. Durch Aufruf von `isEnabled` kann der aktuelle Zustand abgefragt werden:

    public void setEnabled(boolean b)

    public boolean isEnabled()
| java.awt.MenuItem

### 30.4.2 CheckboxMenuItem

Neben der Klasse `MenuItem` gibt es mit der Klasse `CheckboxMenuItem` eine zweite Klasse zum Erzeugen von Menüeinträgen. `CheckboxMenuItem` ist aus `MenuItem` abgeleitet und bietet als zusätzliches Feature eine interne Zustandsvariable, die zwischen `true` und `false` umgeschaltet werden kann. Die visuelle Darstellung der Zustandsvariablen erfolgt durch Anfügen oder Entfernen eines Häkchens neben dem Menüeintrag. Der Nutzen der Klasse `CheckboxMenuItem` besteht darin, daß eine logische Programmvariable durch Auswählen des Menüpunkts abwechselnd an- und ausgeschaltet werden kann.

Die Instanzierung eines `CheckboxMenuItem` erfolgt wie bei einem `MenuItem`. Zusätzlich stehen die beiden Methoden `setState` und `getState` zum Setzen und Abfragen des Zustands zur Verfügung:

    public void setState(boolean state)

    public boolean getState()
| java.awt.CheckboxMenuItem

Das folgende Programm stellt alle bisher erwähnten Eigenschaften in einem Beispiel dar. Es leitet dazu die Klasse `MainMenu1` aus `MenuBar` ab und erzeugt im Konstruktor die Menüs und Menüeinträge. Gegenüber der einfachen Instanzierung von `MenuBar` bietet die Ableitung den Vorteil, daß die neue Klasse Methoden zur Verfügung stellen kann, die zum Zugriff auf Menüs oder Menüeinträge verwendet werden können.

    001 /* Listing3001.java */
    002
    003 import java.awt.*;
    004 import java.awt.event.*;
    005
    006 class MainMenu1
    007 extends MenuBar
    008 {
    009   private MenuItem miRueck;
    010   private CheckboxMenuItem miFarbe;
    011
    012   public MainMenu1()
    013   {
    014     Menu m;
    015
    016     //Datei
    017     m = new Menu("Datei");
    018     m.add(new MenuItem("Neu"));
    019     m.add(new MenuItem("Laden"));
    020     m.add(new MenuItem("Speichern"));
    021     m.addSeparator();
    022     m.add(new MenuItem("Beenden"));
    023     add(m);
    024     //Bearbeiten
    025     m = new Menu("Bearbeiten");
    026     m.add((miRueck = new MenuItem("Rueckgaengig")));
    027     m.addSeparator();
    028     m.add(new MenuItem("Ausschneiden"));
    029     m.add(new MenuItem("Kopieren"));
    030     m.add(new MenuItem("Einfuegen"));
    031     m.add(new MenuItem("Loeschen"));
    032     add(m);
    033     //Optionen
    034     m = new Menu("Optionen");
    035     m.add(new MenuItem("Einstellungen"));
    036     m.add((miFarbe = new CheckboxMenuItem("Farbe")));
    037     add(m);
    038     //Rueckgaengig deaktivieren
    039     enableRueckgaengig(false);
    040     //Farbe anschalten
    041     setFarbe(true);
    042   }
    043
    044   public void enableRueckgaengig(boolean ena)
    045   {
    046     if (ena) {
    047       miRueck.setEnabled(true);
    048     } else {
    049       miRueck.setEnabled(false);
    050     }
    051   }
    052
    053   public void setFarbe(boolean on)
    054   {
    055     miFarbe.setState(on);
    056   }
    057 }
    058
    059 public class Listing3001
    060 extends Frame
    061 {
    062   public static void main(String[] args)
    063   {
    064     Listing3001 wnd = new Listing3001();
    065   }
    066
    067   public Listing3001()
    068   {
    069     super("Menüs");
    070     setLocation(100,100);
    071     setSize(400,300);
    072     setMenuBar(new MainMenu1());
    073     setVisible(true);
    074     addWindowListener(new WindowClosingAdapter(true));
    075   }
    076 }
| Listing3001.java

Listing 30.1: Erzeugen von Menüs

Das Programm erzeugt eine Menüzeile mit den drei Einträgen »Datei«, »Bearbeiten« und »Optionen«, die in Abbildung 30.1 dargestellt werden:

Abbildung 30.1: Erzeugen von Menüs

### 30.4.3 Beschleunigertasten

|  |  |  | In den meisten Programmen lassen sich Menüs nicht nur mit der Maus bedienen, sondern über Beschleunigertasten auch mit der Tastatur. Im JDK 1.0 konnten Beschleunigertasten unter Windows 95 ganz einfach dadurch eingefügt werden, daß an beliebiger Stelle im Menütext das Zeichen »&« eingefügt und so die nachfolgende Taste als Beschleuniger definiert wurde. Dies war natürlich nicht portabel, funktionierte nur unter Windows und wurde folglich als Bug angesehen und eliminiert. |  |
Warnung

Das JDK 1.1 implementiert nun ein eigenes Beschleunigerkonzept, das über Plattformgrenzen hinweg funktioniert. Dazu wurde die Klasse `MenuShortcut` eingeführt, mit deren Hilfe Beschleunigertasten definiert und an einzelne Menüeinträge angehängt werden können. Eine Beschleunigertaste ist dabei immer ein einzelnes Zeichen der Tastatur, das zusammen mit der systemspezifischen Umschalttaste für Beschleuniger (`[STRG]` unter Windows und Motif, `[COMMAND]` unter MAC-OS) gedrückt werden muß, um den Menüeintrag aufzurufen.

Um einen Beschleuniger zu definieren, muß zunächst eine Instanz der Klasse `MenuShortcut` erzeugt werden:

    public MenuShortcut(int key)

    public MenuShortcut(int key, boolean useShiftModifier)
| java.awt.MenuShortcut

Der erste Konstruktor erwartet den virtuellen Tastencode der gewünschten Beschleunigertaste (siehe Kapitel 29). Für einfache alphanumerische Zeichen kann hier auch das Zeichen selbst übergeben werden. Die Übergabe einer Funktionstaste ist leider nicht ohne weiteres möglich, denn deren virtuelle Tastencodes überschneiden sich mit den ASCII-Codes der Kleinbuchstaben. Funktionstasten können daher nur dann als Beschleuniger verwendet werden, wenn ihre virtuellen Tastencodes die Umwandlung in Großbuchstaben unverändert überstehen (z.B. `VK_DELETE`). Der zweite Konstruktor erlaubt zusätzlich die Übergabe eines booleschen Parameters `useShiftModifier`, der dafür sorgt, daß der Beschleuniger nur dann greift, wenn neben der systemspezifischen Umschalttaste für Beschleuniger zusätzlich die Taste `[UMSCHALT]` gedrückt wird.

Um einen Beschleuniger an einen Menüpunkt zu binden, ist das `MenuShortcut`-Objekt als zweites Argument an den Konstruktor von `MenuItem` zu übergeben:

    public MenuItem(String label, MenuShortcut s)
| java.awt.MenuItem

Alternativ kann auch die Methode `setShortCut` aufgerufen werden:

    public void setShortcut(MenuShortcut s)
| java.awt.MenuItem

Durch Aufruf von `deleteShortCut` kann der einem Menüeintrag zugeordnete Beschleuniger gelöscht werden:

    public void deleteShortcut()
| java.awt.MenuItem

Aufgrund eines Bugs im AWT (der auch im JDK 1.2 noch enthalten war) muß nach der Definition eines Beschleunigers zusätzlich die Methode `setActionCommand` aufgerufen werden, um den `String`, der beim Auslösen des Beschleunigers an den ActionListener gesendet werden soll, festzulegen:

    public void setActionCommand(String command)
| java.awt.MenuItem

Ohne diesen Aufruf würde ein `null`-Objekt gesendet werden. Eine beispielhafte Aufrufsequenz zur Erzeugung eines Menüeintrags mit Beschleuniger sieht damit so aus:

    001 Menu m;
    002 MenuItem mi;
    003 MenuShortcut ms;
    004
    005 //Datei
    006 m = new Menu("Datei");
    007
    008 ms = new MenuShortcut(KeyEvent.VK_N);
    009 mi = new MenuItem("Neu",ms);
    010 mi.setActionCommand("Neu");
    011 mi.addActionListener(listener);
    012 m.add(mi);

Listing 30.2: Erzeugen eines Menüeintrags mit Beschleuniger

Hier wird der Menüeintrag »Neu« wie im vorigen Beispiel generiert und mit der Beschleunigertaste `[STRG]`+`[N]` ausgestattet.

Das folgende Beispiel zeigt eine Menüleiste mit zwei Menüs »Datei« und »Bearbeiten«, bei denen alle Menüeinträge mit Beschleunigern ausgestattet wurden:

    001 /* MainMenu2.inc */
    002
    003 class MainMenu2
    004 extends MenuBar
    005 {
    006   public MainMenu2()
    007   {
    008     Menu m;
    009     MenuItem mi;
    010     MenuShortcut ms;
    011
    012     //Datei
    013     m = new Menu("Datei");
    014
    015     ms = new MenuShortcut(KeyEvent.VK_N);
    016     mi = new MenuItem("Neu",ms);
    017     mi.setActionCommand("Neu");
    018     m.add(mi);
    019
    020     ms = new MenuShortcut(KeyEvent.VK_L);
    021     mi = new MenuItem("Laden",ms);
    022     mi.setActionCommand("Laden");
    023     m.add(mi);
    024
    025     ms = new MenuShortcut(KeyEvent.VK_S);
    026     mi = new MenuItem("Speichern",ms);
    027     mi.setActionCommand("Speichern");
    028     m.add(mi);
    029
    030     ms = new MenuShortcut(KeyEvent.VK_E);
    031     mi = new MenuItem("Beenden",ms);
    032     mi.setActionCommand("Beenden");
    033     m.add(mi);
    034     add(m);
    035
    036     //Bearbeiten
    037     m = new Menu("Bearbeiten");
    038
    039     ms = new MenuShortcut(KeyEvent.VK_X);
    040     mi = new MenuItem("Ausschneiden",ms);
    041     mi.setActionCommand("Ausschneiden");
    042     m.add(mi);
    043
    044     ms = new MenuShortcut(KeyEvent.VK_C);
    045     mi = new MenuItem("Kopieren",ms);
    046     mi.setActionCommand("Kopieren");
    047     m.add(mi);
    048
    049     ms = new MenuShortcut(KeyEvent.VK_V);
    050     mi = new MenuItem("Einfügen",ms);
    051     mi.setActionCommand("Einfügen");
    052     m.add(mi);
    053     add(m);
    054   }
    055 }
| MainMenu2.inc

Listing 30.3: Menüleisten mit zwei Menüs und Beschleunigertasten

Wir werden später eine Methode vorstellen, die den Aufwand für das Erzeugen und Einfügen von Beschleunigern vermindert.

Die im JDK 1.1 eingeführten Beschleuniger haben Vor- und Nachteile. Ihr Vorteil ist, daß sie einfach zu erzeugen sind und über Plattformgrenzen hinweg funktionieren. Die Nachteile sind allerdings ihre eingeschränkte Funktionalität und die Unterschiede im Look-and-Feel gegenüber den speziellen Beschleunigern des jeweiligen Betriebssystems. So gibt es unter Windows beispielsweise keine Beschleuniger mehr in der Menüleiste (`[ALT]`+Buchstabe), und auch Menüeinträge können nicht mehr mit `[ALT]`+Tastenkürzel aufgerufen werden (sie zeigen auch keinen unterstrichenen Buchstaben mehr an).

Außerdem wird eine Beschleunigertaste zwangsweise an die systemspezifische Umschalttaste gebunden. Es ist damit nicht möglich, einfache Tasten wie `[EINFG]` oder `[ENTF]` als Beschleuniger zu definieren. Des weiteren lassen sich wegen der unglücklichen Umwandlung des virtuellen Tastencodes in Großbuchstaben viele Funktionstasten nicht als Beschleuniger verwenden. Dies sind sicherlich gravierende Restriktionen, die die Bedienung nicht unerheblich einschränken. Es bleibt zu hoffen, daß die nächste Version des AWT hier Verbesserungen bringt und eine umfassendere Menge der plattformspezifischen Features portabel zur Verfügung stellt.

### 30.4.4 Untermenüs

Menüs lassen sich auf einfache Art und Weise schachteln. Dazu ist beim Aufruf der `add`-Methode anstelle einer Instanz der Klasse `MenuItem` ein Objekt der Klasse `Menu` zu übergeben, das das gewünschte Untermenü repräsentiert. Das folgende Beispiel erweitert das Menü »Optionen« der Klasse `MainMenu1` um den Menüeintrag »Schriftart«, der auf ein Untermenü mit den verfügbaren Schriftarten verzweigt (der Code zur Erzeugung des Untermenüs steht in den Zeilen 034 bis 041):

    001 /* MainMenu3.inc */
    002
    003 class MainMenu3
    004 extends MenuBar
    005 {
    006   private MenuItem miRueck;
    007   private CheckboxMenuItem miFarbe;
    008
    009   public MainMenu3()
    010   {
    011     Menu m;
    012
    013     //Datei
    014     m = new Menu("Datei");
    015     m.add(new MenuItem("Neu"));
    016     m.add(new MenuItem("Laden"));
    017     m.add(new MenuItem("Speichern"));
    018     m.addSeparator();
    019     m.add(new MenuItem("Beenden"));
    020     add(m);
    021     //Bearbeiten
    022     m = new Menu("Bearbeiten");
    023     m.add((miRueck = new MenuItem("Rueckgaengig")));
    024     m.addSeparator();
    025     m.add(new MenuItem("Ausschneiden"));
    026     m.add(new MenuItem("Kopieren"));
    027     m.add(new MenuItem("Einfuegen"));
    028     m.add(new MenuItem("Loeschen"));
    029     add(m);
    030     //Optionen
    031     m = new Menu("Optionen");
    032     m.add(new MenuItem("Einstellungen"));
    033
    034     //Untermenü Schriftart
    035     Menu m1 = new Menu("Schriftart");
    036     m1.add(new MenuItem("Arial"));
    037     m1.add(new MenuItem("TimesRoman"));
    038     m1.add(new MenuItem("Courier"));
    039     m1.add(new MenuItem("System"));
    040     m.add(m1);
    041     //Ende Untermenü Schriftart
    042
    043     m.add((miFarbe = new CheckboxMenuItem("Farbe")));
    044     add(m);
    045     //Rueckgaengig deaktivieren
    046     enableRueckgaengig(false);
    047     //Farbe anschalten
    048     setFarbe(true);
    049   }
    050
    051   public void enableRueckgaengig(boolean ena)
    052   {
    053     if (ena) {
    054       miRueck.setEnabled(true);
    055     } else {
    056       miRueck.setEnabled(false);
    057     }
    058   }
    059
    060   public void setFarbe(boolean on)
    061   {
    062     miFarbe.setState(on);
    063   }
    064 }
| MainMenu3.inc

Listing 30.4: Geschachtelte Menüs

Ein Aufruf des Untermenüs wird folgendermaßen dargestellt:

Abbildung 30.2: Geschachtelte Menüs

Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage, Addison Wesley, Version 3.0
<< | < | > | >> | API | © 1998-2002 Guido Krüger, http://www.javabuch.de