Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage
<< | < | > | >> | API | Kapitel 31 - GUI-Dialoge

## 31.3 Modale Dialoge

- 31.3 Modale Dialoge

Modale Dialoge sind solche, die alle Benutzereingaben des Programmes beanspruchen und andere Fenster erst dann wieder zum Zuge kommen lassen, wenn das Dialogfenster geschlossen wird. Eine wichtige Eigenschaft modaler Dialoge ist es, daß im Programm der Aufruf zur Anzeige des Dialogs so lange blockiert, bis der Dialog beendet ist. Auf diese Weise kann an einer bestimmten Stelle im Programm auf eine Eingabe gewartet werden und erst dann mit der Bearbeitung fortgefahren werden, wenn die Eingabe erfolgt ist.

Im AWT des JDK 1.0 gab es einen schwerwiegenden Fehler, durch den das Erzeugen modaler Dialoge unmöglich gemacht wurde. Der Fehler hielt sich bis zur Version 1.0.2 und wurde erst mit Erscheinen des JDK 1.1 behoben. Da viele Anwenderdialoge von Natur aus modalen Charakter haben, wurde dieser Fehler von vielen als schwerwiegend angesehen, und die Java-Gemeinde entwickelte eine Reihe von Workarounds, die aber allesamt nicht voll zufriedenstellen konnten. Glücklicherweise wurden die Probleme mit dem JDK 1.1 behoben, und wir wollen in diesem Kapitel aufzeigen, wie modale Dialoge in Java erzeugt werden können.

Ein modaler Dialog muß immer aus der Klasse `Dialog` abgeleitet werden. Nur sie bietet die Möglichkeit, an den Konstruktor einen booleschen Wert zu übergeben, der festlegt, daß die übrigen Fenster der Anwendung während der Anzeige des Dialogs suspendiert werden. `Dialog` besitzt folgende Konstruktoren:

    public Dialog(Frame owner)

    public Dialog(Frame owner, boolean modal)

    public Dialog(Frame owner, String title)

    public Dialog(Frame owner, String title, boolean modal)

    public Dialog(Dialog owner)

    public Dialog(Dialog owner, String title)

    public Dialog(Dialog owner, String title, boolean modal)
| java.awt.Dialog

Als erstes Argument muß in jedem Fall ein `Frame`- oder `Dialog`-Objekt als Vaterfenster übergeben werden (bis zur Version 1.1 waren nur `Frame`-Objekte erlaubt). Mit `title` kann der Inhalt der Titelzeile vorgegeben werden, und der Parameter `modal` entscheidet, ob der Dialog modal dargestellt wird oder nicht.

`Dialog` bietet die Methoden `isModal` und `setModal`, mit denen auf die Modalität des Dialogs zugegriffen werden kann:

    public boolean isModal()

    public void setModal(boolean b)
| java.awt.Dialog

Der Rückgabewert von `isModal` ist `true`, falls der Dialog modal ist. Andernfalls ist er `false`.

|  |  |  | Die Methode `setModal`, deren Fähigkeit darin besteht, einen bestehenden Dialog zwischen den Zuständen modal und nicht-modal umzuschalten, ist mit Vorsicht zu genießen. Unter Windows 95 hat ein Aufruf im JDK 1.1 mitunter dazu geführt, daß beim Schließen des Fensters die Nachrichtenschleife des Aufrufers deaktiviert blieb und das Programm sich aufhängte. Am besten, man entscheidet schon im Konstruktor, ob der Dialog modal sein soll oder nicht. |  |
Warnung

Ein zusätzliches Feature der Klasse `Dialog` besteht darin, die Veränderbarkeit der Größe eines Fensters durch den Anwender zu unterbinden:

    public void setResizable(boolean resizable)

    public boolean isResizable()
| java.awt.Dialog

Nach einem Aufruf von `setResizable` mit `false` als Argument kann die Größe des Fensters nicht mehr vom Anwender verändert werden. Nach einem Aufruf von `setResizable(true)` ist dies wieder möglich. Mit `isResizable` kann der aktuelle Zustand dieses Schalters abgefragt werden.

|  |  |  | Auch die Methode `setResizable` ist nicht ganz unkritisch, denn sie hat auf einigen UNIX-Systemen zu Problemen geführt. Sowohl unter SUN Solaris als auch unter LINUX kam es im JDK 1.1 zu Hängern bei Programmen, die diese Methode benutzten. Falls sich die nachfolgenden Beispielprogramme auf Ihrem System nicht so verhalten wie angegeben (typischerweise wird der Dialog gar nicht erst angezeigt), sollten Sie versuchsweise den Aufruf von `setResizable` auskommentieren. |  |
Warnung

Das folgende Beispiel demonstriert die Anwendung der Klasse `Dialog`. Es zeigt einen `Frame`, aus dem per Buttonklick ein modaler Dialog aufgerufen werden kann. Der Dialog fragt den Anwender, ob die Anwendung beendet werden soll, und wartet, bis einer der Buttons »Ja« oder »Nein« gedrückt wurde. In diesem Fall wird ein boolescher Rückgabewert generiert, der nach dem Schließen des Dialogs an das Vaterfenster zurückgegeben wird. Falls der Rückgabewert `true` (entprechend dem Button »Ja«) ist, wird die Anwendung beendet, andernfalls läuft sie weiter:

    001 /* Listing3110.java */
    002
    003 import java.awt.*;
    004 import java.awt.event.*;
    005
    006 class YesNoDialog
    007 extends Dialog
    008 implements ActionListener
    009 {
    010   boolean result;
    011
    012   public YesNoDialog(Frame owner, String msg)
    013   {
    014     super(owner, "Ja-/Nein-Auswahl", true);
    015     //Fenster
    016     setBackground(Color.lightGray);
    017     setLayout(new BorderLayout());
    018     setResizable(false); //Hinweis im Text beachten
    019     Point parloc = owner.getLocation();
    020     setLocation(parloc.x + 30, parloc.y + 30);
    021     //Message
    022     add(new Label(msg), BorderLayout.CENTER);
    023     //Buttons
    024     Panel panel = new Panel();
    025     panel.setLayout(new FlowLayout(FlowLayout.CENTER));
    026     Button button = new Button("Ja");
    027     button.addActionListener(this);
    028     panel.add(button);
    029     button = new Button("Nein");
    030     button.addActionListener(this);
    031     panel.add(button);
    032     add(panel, BorderLayout.SOUTH);
    033     pack();
    034   }
    035
    036   public void actionPerformed(ActionEvent event)
    037   {
    038     result = event.getActionCommand().equals("Ja");
    039     setVisible(false);
    040     dispose();
    041   }
    042
    043   public boolean getResult()
    044   {
    045     return result;
    046   }
    047 }
    048
    049 public class Listing3110
    050 extends Frame
    051 implements ActionListener
    052 {
    053   public static void main(String[] args)
    054   {
    055     Listing3110 wnd = new Listing3110();
    056     wnd.setVisible(true);
    057   }
    058
    059   public Listing3110()
    060   {
    061     super("Modale Dialoge");
    062     setLayout(new FlowLayout());
    063     setBackground(Color.lightGray);
    064     Button button = new Button("Ende");
    065     button.addActionListener(this);
    066     add(button);
    067     setLocation(100,100);
    068     setSize(300,200);
    069     setVisible(true);
    070   }
    071
    072   public void actionPerformed(ActionEvent event)
    073   {
    074     String cmd = event.getActionCommand();
    075     if (cmd.equals("Ende")) {
    076       YesNoDialog dlg;
    077       dlg = new YesNoDialog(
    078         this,
    079         "Wollen Sie das Programm wirklich beenden?"
    080       );
    081       dlg.setVisible(true);
    082       //Auf das Schließen des Dialogs warten...
    083       if (dlg.getResult()) {
    084         setVisible(false);
    085         dispose();
    086         System.exit(0);
    087       }
    088     }
    089   }
    090 }
| Listing3110.java

Listing 31.10: Konstruktion modaler Dialoge

|  | Um den Dialog relativ zur Position seines Vaterfensters anzuzeigen, wird dessen Position durch Aufruf von `getLocation` ermittelt. Der Ursprung des Dialogfensters wird dann 30 Pixel weiter nach unten bzw. nach rechts gelegt. |  |
Hinweis

Nach dem Start zeigt das Programm zunächst das in Abbildung 31.14 dargestellte Fenster an:

Abbildung 31.14: Das Vaterfenster für den modalen Dialog

Nach dem Klick auf »Ende« wird `actionPerformed` aufgerufen und läuft bis zum Aufruf des Dialogs (siehe Abbildung 31.15). Die Anweisung `dlg.setVisible(true);` ruft den Dialog auf und blockiert dann. Sie terminiert erst, wenn der Dialog durch Drücken eines Buttons beendet wurde. In diesem Fall wird mit `getResult` der Rückgabewert abgefragt und das Programm beendet, wenn dieser `true` ist. Die Methode `getResult` liefert den Inhalt der privaten Instanzvariablen `result`, die beim Auftreten eines Action-Events durch einen der beiden Buttons gesetzt wird. Zwar ist das Dialogfenster beim Aufruf von `getResult` bereits zerstört, aber die Objektvariable `dlg` existiert noch und `getResult` kann aufgerufen werden.

Abbildung 31.15: Ein einfacher Ja-/Nein-Dialog

Bevor wir das Kapitel beenden, wollen wir dieses Programm ein wenig erweitern und ein weiteres Beispiel für die Anwendung modaler Dialoge geben. Das folgende Programm implementiert eine Klasse `ModalDialog`, die aus `Dialog` abgeleitet ist. Mit ihrer Hilfe können modale Dialoge der obigen Art konstruiert werden, bei denen die Ausstattung mit Buttons variabel ist und zum Zeitpunkt der Instanzierung festgelegt werden kann:

    public ModalDialog(
       Frame owner,
       String title,
       String msg,
       String buttons
    );

Der Konstruktor erwartet neben dem Vater-`Frame` drei weitere Parameter, `title`, `msg` und `buttons`. In `title` wird der Inhalt der Titelzeile übergeben, und `msg` spezifiziert den Text innerhalb des Dialogs. Der Parameter `buttons` erwartet eine Liste von `Button`-Bezeichnern, die zur Festlegung der Anzahl und Beschriftung der Buttons dienen. Die einzelnen Elemente sind durch Kommata zu trennen und werden innerhalb des Dialogs mit einem `StringTokenizer` zerlegt. Der in `getResult` gelieferte Rückgabewert des Dialogs ist - anders als im vorigen Beispiel - ein `String` und entspricht der Beschriftung des zum Schließen verwendeten Buttons.

`ModalDialog` enthält einige statische Methoden, mit denen Dialoge mit einer festen Buttonstruktur einfach erzeugt werden können. So erzeugt `OKButton` lediglich einen Button mit der Beschriftung »OK«, `YesNoDialog` zwei Buttons, »Ja« und »Nein«, und `YesNoCancelDialog` erzeugt einen Dialog mit drei Buttons, »Ja«, »Nein« und »Abbruch«. Das folgende Listing zeigt die Klasse `ModalDialog` und ein Rahmenprogramm zum Testen:

    001 /* Listing3111.java */
    002
    003 import java.awt.*;
    004 import java.awt.event.*;
    005 import java.util.*;
    006
    007 class ModalDialog
    008 extends Dialog
    009 implements ActionListener
    010 {
    011   String result;
    012
    013   public static String OKDialog(Frame owner, String msg)
    014   {
    015     ModalDialog dlg;
    016     dlg = new ModalDialog(owner,"Nachricht",msg,"OK");
    017     dlg.setVisible(true);
    018     return dlg.getResult();
    019   }
    020
    021   public static String YesNoDialog(Frame owner, String msg)
    022   {
    023     ModalDialog dlg;
    024     dlg = new ModalDialog(owner,"Frage",msg,"Ja,Nein");
    025     dlg.setVisible(true);
    026     return dlg.getResult();
    027   }
    028
    029   public static String YesNoCancelDialog(Frame owner,String msg)
    030   {
    031     ModalDialog dlg;
    032     dlg = new ModalDialog(owner,"Frage",msg,"Ja,Nein,Abbruch");
    033     dlg.setVisible(true);
    034     return dlg.getResult();
    035   }
    036
    037   public ModalDialog(
    038     Frame owner,
    039     String title,
    040     String msg,
    041     String buttons
    042   )
    043   {
    044     super(owner, title, true);
    045     //Fenster
    046     setBackground(Color.lightGray);
    047     setLayout(new BorderLayout());
    048     setResizable(false);
    049     Point parloc = owner.getLocation();
    050     setLocation(parloc.x + 30, parloc.y + 30);
    051     //Message
    052     add(new Label(msg), BorderLayout.CENTER);
    053     //Buttons
    054     Panel panel = new Panel();
    055     panel.setLayout(new FlowLayout(FlowLayout.CENTER));
    056     StringTokenizer strtok = new StringTokenizer(buttons,",");
    057     while (strtok.hasMoreTokens()) {
    058       Button button = new Button(strtok.nextToken());
    059       button.addActionListener(this);
    060       panel.add(button);
    061     }
    062     add(panel, BorderLayout.SOUTH);
    063     pack();
    064   }
    065
    066   public void actionPerformed(ActionEvent event)
    067   {
    068     result = event.getActionCommand();
    069     setVisible(false);
    070     dispose();
    071   }
    072
    073   public String getResult()
    074   {
    075     return result;
    076   }
    077 }
    078
    079 public class Listing3111
    080 extends Frame
    081 implements ActionListener
    082 {
    083   public static void main(String[] args)
    084   {
    085     Listing3111 wnd = new Listing3111();
    086     wnd.setVisible(true);
    087   }
    088
    089   public Listing3111()
    090   {
    091     super("Drei modale Standarddialoge");
    092     setLayout(new FlowLayout());
    093     setBackground(Color.lightGray);
    094     Button button = new Button("OKDialog");
    095     button.addActionListener(this);
    096     add(button);
    097     button = new Button("YesNoDialog");
    098     button.addActionListener(this);
    099     add(button);
    100     button = new Button("YesNoCancelDialog");
    101     button.addActionListener(this);
    102     add(button);
    103     setLocation(100,100);
    104     setSize(400,200);
    105     setVisible(true);
    106   }
    107
    108   public void actionPerformed(ActionEvent event)
    109   {
    110     String cmd = event.getActionCommand();
    111     if (cmd.equals("OKDialog")) {
    112       ModalDialog.OKDialog(this,"Dream, dream, dream, ...");
    113     } else if (cmd.equals("YesNoDialog")) {
    114       String ret = ModalDialog.YesNoDialog(
    115         this,
    116         "Programm beenden?"
    117       );
    118       if (ret.equals("Ja")) {
    119         setVisible(false);
    120         dispose();
    121         System.exit(0);
    122       }
    123     } else if (cmd.equals("YesNoCancelDialog")) {
    124       String msg = "Verzeichnis erstellen?";
    125       String ret = ModalDialog.YesNoCancelDialog(this,msg);
    126       ModalDialog.OKDialog(this,"Rückgabe: " + ret);
    127     }
    128   }
    129 }
| Listing3111.java

Listing 31.11: Drei modale Standarddialoge

Die drei Dialoge, die durch Aufrufe von `OKDialog`, `YesNoDialog` und `YesNoCancelDialog` generiert werden, sind in den folgenden Abbildungen 31.16 bis 31.18 dargestellt:

Abbildung 31.16: Ein Aufruf von OKDialog

Abbildung 31.17: Ein Aufruf von YesNoDialog

Abbildung 31.18: Ein Aufruf von YesNoCancelDialog

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