Titel   Inhalt   Suchen   Index   API  Go To Java 2, Zweite Auflage, Handbuch der Java-Programmierung
 <<    <     >    >>  Kapitel 31 - GUI-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("Center", new Label(msg));
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("South", panel);
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("Center", new Label(msg));
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("South", panel);
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   API  Go To Java 2, Zweite Auflage, Addison Wesley, Version 2.0
 <<    <     >    >>  © 2000 Guido Krüger, http://www.gkrueger.com