Auf Fensterschließen warten

d4rkY89

Mitglied
Methode soll auf "Fensterschließen" warten

Hallo !
Ich stehe mal wieder vor einem Problem:
Ich würde gerne eine Methode schreiben, die mir Werte zurückgibt, die in einem neuen Fenster (JDialog) eingegeben werden und mit einem Button bestätigt werden sollen. Die Methode muss also nach Aufruf warten, bis in dem neu erzeugten Fenster der Button geklickt worden ist und dann die Werte auslesen und diese schließlich zurückgeben.

Ich habe mir schon den Source-Code von JFileChooser und vom JOptionPane angeschaut, da man dort eben auch eine Methode aufruft und diese liefert erst einen Wert zurück, nachdem das Fenster geschlossen worden ist. Allerdings wurde ich nicht ganz schlau aus dem Source-Code und hab dieses "Schlüsselelement" nicht entdecken können, wodurch eben die Methode auf das Schließen oder das Drücken eines Buttons des Fensters wartet.

Es sollte nun relativ klar sein, was ich meine und ich hoffe, dass jemand von euch eine Ahnung hat. Mir ist auch kein Suchbegriff für dieses Problem eingefallen, der mir eine Lösung gebracht hat. Bin für jede Hilfe dankbar. :)
 
Zuletzt bearbeitet:
Hallo.

Vielleicht hilft Dir ein WindowListener weiter, den Du dem Dialog zuweist.

Vor Allem
public void windowClosing(WindowEvent e) { do what I want... }
könnte für Dich interessant sein. Lass Dir den Dialog anzeigen und führe beim Schließen eine Methode aus, die Deine gewünschte Bearbeitung startet.

Gruß, Martin
 
Nein, ich denke nicht, dass hier nen WinowListener die Lösung ist. Und wenn doch, dann wüsste ich nicht, wie ich ihn in diesem Fall anzuwenden habe.
Die Methode wartet ja nicht darauf, bis die Methode windowClosing() aufgerufen wird. Das Problem bei der Sache ist, dass das neue JDialog, wie auch andere Fenster, in einem eigenen Thread laufen. Sprich, wenn ich die Methode ausführe, läuft sie einfach bis zum "return object;" weiter. Ich hab mir schon gedacht, dass ich die Überschift dieses Threads leicht unglücklich gewählt habe :D
Aber danke für deine Antwort :)
 
Zuletzt bearbeitet:
Um euch ein Beispiel zu geben:

Java:
public class InputFrame {
    private InputFrame() extends JDialog {
    //Frame wird initialisiert
    }

    private String getName() {
        return ....;
    }

    public static String getName() {
        InputFrame if = new InputFrame();
        //Hier muss die Methode warten, bis das Fenster geschlossen ist
        //oder ein Button wie "OK" gedrückt worden ist.
        //Da das Fenster aber ein eigener Thread ist, läuft die Methode einfach
        //weiter zum return...
        if.dispose();
        return if.getName();
    }
}

Ich bin mir sicher, dass die Lösung irgendwo im Source-Code vom JOptionPane steckt aber da blick ich nicht mehr ganz durch.
Wenn jemand, der da einen Durchblick hat, ein kleines Beispiel wie oben posten könnte, würde mich das sehr freuen ;)
 
Zuletzt bearbeitet:
Guten Morgen.

Kannst Du folgendes in Deine Programmstruktur implementieren:

Methode 1 ruft den Dialog auf und macht sonst nichts.
Wenn bei dem Dialog der Button gedrückt wird (oder der Dialog eben geschlossen wird - WindowListener), wird eine zweite Methode aufgerufen, welche die Bearbeitung durchführt, die Du eigentlich erst nach dem Schließen des Dialogs durchführen wolltest.

Wenn Du alles in eine Methode packen willst, dann fällt mir auf die Schnelle leider auch keine Lösung ein.

Gruß, Martin
 
Zuletzt bearbeitet:
Ich weiß nicht, ob das eine gute Lösung ist, aber es ist zumindest eine Idee...

Hier meine Codes...

Main.java
Java:
package dialogmitrueckgabe;

public class Main {
	public static void main(String[] args) {
		String str = OptionDialogs.showInputDialog("Gib was ein", "Test");
		if(str == null) {
			System.out.println("Ich hab doch gesagt, du sollst was eingeben o.O");
		} else {
			System.out.println(str);
		}
	}
}

OptionDialogs.java
Java:
package dialogmitrueckgabe;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class OptionDialogs {
	private static String strValue = null;
	
	public static String showInputDialog(String msg, String title) {
		// Rückgabe-Wert auf null setzen
		strValue = null;
		
		/*
		 *  Den Dialog, der gezeigt werden soll, erstellen ...
		 *  
		 *  Der Dialog beinhaltet:
		 *  - ein Label mit einer Aufforderung
		 *  - ein Eingabe-Textfeld
		 *  - ein OK-Button
		 */
		// Dialog erstellen und konfigurieren
		final JDialog dialog = new JDialog();
		dialog.setTitle(title);
		dialog.setLayout(new GridLayout(3, 1));
		dialog.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent event) {
				// Wenn das Fenster geschlossen wird, soll der Rückgabewert null sein
				strValue = null;
				event.getWindow().dispose();
			}
		});
		
		// Dialog-Elemente einfügen (Label, Textfeld, Button)
		Container cp = dialog.getContentPane();
		JLabel lb = new JLabel(msg);
		cp.add(lb);
		
		final JTextField tf = new JTextField();
		cp.add(tf);
		
		JButton bt = new JButton("OK");
		bt.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				// Textfeld-Inhalt als Rückgabewert speichern
				strValue = tf.getText();
				
				// Und den Dialog schließen
				dialog.dispose();
			}
		});
		cp.add(bt);
		
		// Dialog (mehr oder weniger) dynamisch erstellen und zeigen
		dialog.pack();
		dialog.setSize(200, dialog.getHeight());
		dialog.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - dialog.getWidth()) / 2,
							(Toolkit.getDefaultToolkit().getScreenSize().height - dialog.getHeight()) / 2);
		dialog.setVisible(true);
		
		// Solange der Dialog "da" ist, soll nix passieren => Leere Endlosschleife
		while(dialog.isShowing());
		
		// Wenn der Dialog geschlossen wurde (auf welche Weise auch immer),
		// dann wird ein Wert zurückgegeben
		return strValue;
	}
}

Erklärung:
In meinem Beispiel wird ein Dialog über eine statische Methode aufgerufen. Diese Methode erstellt einen Dialog, dessen Aufgabe es ist, den Benutzer nach einer Eingabe aufzufordern. Die Methode wartet nach der Erstellung des Dialogs darauf, dass der Dialog verschwindet und fährt erst dann mit der Verarbeitung fort.

Den Textfeld-Inhalt bekommt man über einen ActionListener auf dem OK-Button und kann anschließend zurückgegeben werden.

Hoffe, das hilft ein wenig ^^

EDIT:
Mir is grad aufgefallen, dass es etwas unübersichtlich ist, den Dialog mitten in der Methode zu konfigurieren. Bei komplexeren Dialogen würde ich lieber einen eigenen Dialog aus JDialog ableiten. Dann muss aber eine Referenz für den Rückgabewert übergeben werden, da man sonst nicht an ihn drankommen würde.
 
Zuletzt bearbeitet:
Hi
Danke erst mal für eure Antworten.
@martin1981ww:
Die Idee in deinem Vorschlag will ich gerade in meinem Programm vermeiden. ^^ :)

@Akeshihiro:
Dein Lösungsansatz ist natürlich auch 'ne Idee, die ich wohl implementieren werde, obwohl hier eine while-Schleife nicht unbedingt eine schöne Lösung ist denke ich. Auch sollte man dabei 'nen "Thread.sleep(...)" in die while-Schleife einbauen, da diese sonst bei CPUs mit nur einem Kern den Rechner ziemlich lahmlegen würde. :D
Aber es hilft mir schon mal weiter, danke.


Vielleicht findet sich ja noch jemand, der herausfindet, wie es z.B. im JOptionPane realisiert ist. Wenn ich mal wieder mehr Zeit habe versuch ich auch nochmal mein Glück.
 
Zuletzt bearbeitet:
Hi,
also zunächst muss man überlegen, ob der Dialog modal ist oder nicht.
In den meisten Fällen, und so las ich es auch in Deiner Schilderung heraus soll es wohl ein modaler Dialog sein, also ein Dialogfesnter geht auf und das Hauptfenster kann vom Anwender daraufhin nicht geändert bzw. in den Focus gebracht werden.

Bei einem nicht Modalen Dialog würde ich mit Listenern arbeiten, hier aber offenbar nicht notwendig.

Ist der Dialog also modal wird die Routine "zeige mal den Dialog", dort wo sie aufgerufen wurde, solange "stecken bleiben", bis der JDialog wieder geschlossen wird, wobei Du das Dialogobjekt dann immernoch abfragen kannst, solange Du noch eine Referenz darauf hälst. Die Werte die der Anwender dann im Dialog gewählt/eingegeben hat, würde ich dann mit get-Routinen In meinem darübergeordneten Programm abfragen und nach Wusnch verwenden.

Also eigetnlich gar nicht so kompliziert wie man erst denken würde.


PS: In der Initialisierung des Dialoges, ich würde dies in einer separaten init-Routine tun, kannst Du mit setDefaultCloseOperation(DISPOSE_ON_CLOSE); Angeben, dass es beim schließen des Dialoges zu einem dispose kommen soll. Die aktion eines OK-Buttons würde ich auch zum Schluss eine dispose(); verwenden
 
Wow, danke Dir! ;-]
also es funktioniert einwandfrei. So lernt man wieder was dazu. Ich wusste garnicht, dass es mit einem JDialog automatisch geht. ^^

Falls noch Andere daran interessiert sind hab ich hier mal meinen Testcode:
Java:
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;

public class TestDialog extends JDialog {
	public static void main(String[] args) {
		JFrame frame = new JFrame("Test");
		frame.setSize(400, 400);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);

		TestDialog dialog = new TestDialog(frame, true);
		dialog.setVisible(true);

		System.out.println(dialog.getInputData());
		System.exit(0);
	}

	private String testData = null;

	public TestDialog(Frame frame, boolean modal) {
		super(frame, modal);

		add(new JButton(new ApproveAction()), BorderLayout.CENTER);

		pack();
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		setResizable(false);
		setLocationRelativeTo(frame);
	}

	private class ApproveAction extends AbstractAction {
		private ApproveAction() {
			super("Ok");
		}

		public void actionPerformed(ActionEvent ae) {
			testData = "Testdaten";
			dispose();
		}
	}

	public String getInputData() {
		return testData;
	}
}

Ist jetzt nicht ganz so schön geschrieben, da man das JFrame eventuell noch in eine eigene Klasse packen würde um es zu initialisieren ect. genauso die Main-Methode. Aber es ist ja nur zu Testzwecken gewesen :D

Noch ein kleiner Hinweis:
Nach dem Initialisieren des JDialogs ist kein setVisible(true) mehr nötig. Dies hätte zur Folge, dass der Dialog 2 mal angezeigt werden würde. Das erste mal durch "setVisible(true)' und einmal durch irgendeinen internen Aufruf.
 
Zuletzt bearbeitet:
Aha, sehr interessant... Hab ich auch was dazugelernt ^^ Der Trick liegt also darin, den Dialog modal zu machen ... Ich wusst gar nicht, dass das die Ausführung des restlichen Programms stoppen kann, dachte das is nur dazu da, dass man nicht mehr im Besitzerfenster klickern kann.
 
Zurück