Tit   Inh   Ind   1   2   3   4   5   6   7   8   9   10   11   12   13   14   15   16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32   <<   <   >   >> 

21.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 /* Listing2110.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 Listing2110
050 extends Frame
051 implements ActionListener
052 {
053    public static void main(String[] args)
054    {
055       Listing2110 wnd = new Listing2110();
056       wnd.setVisible(true);
057    }
058 
059    public Listing2110()
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 }
Listing2110.java
Listing 21.10: Konstruktion modaler Dialoge

 Beispiel 

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 21.14 dargestellte Fenster an:

Abbildung 21.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 21.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 21.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
);
 Beispiel 

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:

 Tip 

001 /* Listing2111.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 Listing2111
080 extends Frame
081 implements ActionListener
082 {
083    public static void main(String[] args)
084    {
085       Listing2111 wnd = new Listing2111();
086       wnd.setVisible(true);
087    }
088 
089    public Listing2111()
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 }
Listing2111.java
Listing 21.11: Drei modale Standarddialoge

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

Abbildung 21.16: Ein Aufruf von OKDialog

Abbildung 21.17: Ein Aufruf von YesNoDialog

Abbildung 21.18: Ein Aufruf von YesNoCancelDialog


 Tit   Inh   Ind   1   2   3   4   5   6   7   8   9   10   11   12   13   14   15   16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32   <<   <   >   >> 
Go To Java 2, Addison Wesley, Version 1.0.2, © 1999 Guido Krüger, http://www.gkrueger.com