Titel | Inhalt | Suchen | Index | API | Go To Java 2, Zweite Auflage, Handbuch der Java-Programmierung |
<< | < | > | >> | Kapitel 31 - GUI-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. |
|
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. |
|
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 |
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. |
|
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 |
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 |