Java Dialog abwarten und Ergebnis übermitteln

Kamikatze

Captain
Registriert
Okt. 2004
Beiträge
3.703
Hallo!

Wie kann ich am besten auf das Ergebnis eines eigenen Dialogs warten und dieses dann per return zurückgeben? Quasi dasselbe wie die JOptionPane-Dialoge, nur mit komplexeren, selbsterstellten Dialogen.

Ich vermute mal, dass ich nur die von Netbeans standardmäßig erstellte Methode der Dialog-Klasse irgendwie anpassen müsste, so dass sie wartet, bis der Dialog geschlossen wurde und dann eben das Ergebnis zurückgibt.

Code:
 public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                NameChooser dialog = new NameChooser(new javax.swing.JFrame(), true);
                dialog.addWindowListener(new java.awt.event.WindowAdapter() {

                    @Override
                    public void windowClosing(java.awt.event.WindowEvent e) {
                        System.exit(0);
                    }
                });
                dialog.setVisible(true);
            }
        });
    }

Also aus
Code:
public static void main(String args[])
würde dann
Code:
public static String showNameChooserDialog(...)
werden.

Aber wo/wie gebe ich dann das nach Schließen des Dialogs in einer meiner Variablen stehende Ergebnis zurück?

Danke!
 
Danke. Da war ich heute schon. Entweder ich bin blind oder einfach nur anpassen ist zu wenig. Meine Dialoge sind komplette Programme samt Programmlogik und etlichen Steuerelementen, die nach Beendigung eben etwas zurückgeben sollen.
 
Code:
public class Example {

	private class ReturningDialog extends JDialog {

		private String choosenName;

		public ReturningDialog(Frame parent) {
			super(parent, "Choose!", true);
			setLayout(new BorderLayout());

			final JTextField input = new JTextField(20);
			final JButton btn = new JButton("Ok");

			btn.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					choosenName = input.getText();
					dispose();
				}
			});

			add(input, BorderLayout.CENTER);
			add(btn, BorderLayout.SOUTH);
			pack();
			setLocation(parent.getX() + 50, parent.getY() + 50);
		}

		public String getChoosenName() {
			return choosenName;
		}
	}

	public Example() {
		final JFrame parentFrame = new JFrame("Parent");
		final JButton btn = new JButton("Choose a name!");

		btn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				System.out.println(showNameChooser(parentFrame));
			}
		});

		parentFrame.add(btn);
		parentFrame.pack();
		parentFrame.setLocation(400, 400);
		parentFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		parentFrame.setVisible(true);
	}

	public static void main(String[] args) {
		new Example();
	}

	private String showNameChooser(Frame parent) {
		ReturningDialog dialog = new ReturningDialog(parent);
		dialog.setVisible(true);
		return dialog.getChoosenName();
	}
}

Bei Erklärungsbedarf einfach melden...
 
Hallo und danke für die weiteren Antworten.

@Killkrog:
Wenn ich mich jetzt nicht täusche, gibt diese Methode auch nur den aktuellen Zustand der Variable zurück, anstatt zu warten bis der Dialog beendet wurde und dann ein gültiges Ergebnis zu liefern?

Um noch etwas konkreter zu werden: In meinem Programm gibt es auch kein Hauptfenster, das ganze Programm ist eine Konsolenanwendung, die im Idealfall gar keine Interaktion benötigt.

In der Schleife des Algorithmus wird automatisch ein String erzeugt, kommt es jedoch zu einem Konfliktfall, soll der Dialog erscheinen und nach Klick auf OK das Ergebnis zurückgegeben werden. Erst dann kann der Algorithmus an dieser Stelle fortfahren.

Ich brauche also einen blockierende (synchrone) Dialog-Funktion, genau wie JOptionPane das macht, nur ist mein Dialog kein simpler Eingabedialog, sondern eben ein komplettes kleines graphisches Programm.
 
Kamikatze schrieb:
Wenn ich mich jetzt nicht täusche, gibt diese Methode auch nur den aktuellen Zustand der Variable zurück, anstatt zu warten bis der Dialog beendet wurde und dann ein gültiges Ergebnis zu liefern?
Du täuscht dich. Hast du das Programm überhaupt ausgeführt?

// edit
Übrigens, blockierende und synchrone Methoden sind zweierlei verschiedene Dinge, falls du das mit dem eingeklammerten Zusatz andeuten wolltest.
 
Zuletzt bearbeitet: (Ergänzung)
Killkrog schrieb:
Du täuscht dich. Hast du das Programm überhaupt ausgeführt?

Ich wollte, um meine Vermutung zu überprüfen, hab es aber auf die schnelle nicht zum laufen gebracht. Irgendwie habe ich die Funktionsweise dann aber wirklich nicht ganz verstanden. Wie würde ich das dann denn in meiner anderen Klasse verwenden?

Killkrog schrieb:
// edit
Übrigens, blockierende und synchrone Methoden sind zweierlei verschiedene Dinge, falls du das mit dem eingeklammerten Zusatz andeuten wolltest.

Dann meinte ich wohl einen synchronen Methoden-Aufruf:
Beim synchronen Aufruf einer Methode wird der aufrufende Thread blockiert, solange die aufgerufene Methode noch aktiv ist. Nach dem Ende des Arbeitsschritts gibt die Methode ihre Ergebnisse an den Aufrufer zurück. Da der Aufruf synchron erfolgt, weiß der aufrufende Code, dass die Methode garantiert bis zu einem der vorgesehenen Rückkehrpunkte durchgelaufen ist. Damit ist sichergestellt, dass die zurückgegebenen Werte gültig sind (sofern der Code fehlerfrei ist).
 
@Killkrog
Natürlich war das Teil seiner Frage. Nur weil du ein true in deinem Konstruktoraufruf drin hast, heißt das nicht, dass der TE auch versteht was modale Dialoge sind.

@Kamikatze
Les dir mal meinen Beitrag und den Link durch, da wird das mit "blockieren" erklärt. Was du suchst ist ein Modaler Dialog. So macht das auch die JOptionPane.
 
Zuletzt bearbeitet:
samotyr schrieb:
@Killkrog
Natürlich war das Teil seiner Frage. Nur weil du ein true in deinem Konstruktoraufruf drin hast, heißt das nicht, dass der TE auch versteht was modale Dialoge sind.

Nicht nur ich hatte es in meinem Code, sondern er auch, noch vor mir. Da ich erwarte, dass die Leute wissen, was ihr eigener Code macht, gehe ich davon aus, dass er weiß, was modale Dialoge sind.

@TE
Ein anderes Beispiel. Um es "zum Laufen zu bringen"... In eine Datei kopieren, diese "CommandLineProgram.java" nennen, compilieren und ausführen.

Code:
public class CommandLineProgram {

	public CommandLineProgram() {
		String s = calculateString();

		System.out.println("CommandLineProgram calculated: \"" + s + "\"");
	}

	private String calculateString() {

		// Sei dies dein Algorithmus, der deinen String generiert und im Falle von "0" einen Konflikt
		// simuliert...
		String generatedString = String.valueOf((int) (Math.random() * 3));

		if (generatedString.equals("0")) { // 'Konflikt', also Benutzereingabe fordern
			return getUserInput();
		} else { // Kein 'Konflikt', also Ergebnis sofort zurückliefern
			return generatedString;
		}
	}

	private String getUserInput() {
		final JDialog dialog = new JDialog((Frame) null, "Eingabe erforderlich", true);
		dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		dialog.setLayout(new BorderLayout(2, 2));

		JTextField input = new JTextField(20);
		dialog.add(input, BorderLayout.CENTER);

		JButton btn = new JButton("OK");
		btn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				dialog.dispose();
			}
		});
		dialog.add(btn, BorderLayout.SOUTH);

		dialog.pack();
		dialog.setLocation(500, 500);
		dialog.setVisible(true);

		return input.getText();
	}

	public static void main(String[] args) {
		new CommandLineProgram();
	}
}

Ich glaub noch krasser kann ich es gar nicht mehr auf deine Bedürfnisse zurechtschneidern, außer dass ich dir das Programm komplett schreib ;)
 
Killkrog schrieb:
Nicht nur ich hatte es in meinem Code, sondern er auch, noch vor mir.
Ups, hast recht. Muss ich wohl übersehen haben.

Auf der anderen Seite scheine ich das Problem nicht ganz nachvollziehen zu können. Ein modaler Dialog ist ja grade dazu da, das Hauptfenster stoppen zu lassen, bis der Dialog beendet wurde. Nun ja, wie dem auch sei, ich ziehe mich dann aus dem Thread zurück.

Viel Erfolg noch an den TE.
 
Ich würde es wie folgt abhandeln:

1. drei Klassen erstellen.
2. In die erste Klasse packst Du diesen Code:

In der Schleife des Algorithmus wird automatisch ein String erzeugt, [...]

3. In die zweite Klasse packst Du den Code:


kommt es jedoch zu einem Konfliktfall, soll der Dialog erscheinen und nach Klick auf OK das Ergebnis zurückgegeben werden.


4. In die dritte Klasse packst Du die main Methode, in der Du jeweils beide Klassen instantiierst. Daraufhin würde ich vom rein logischen Ansatz so etwas verfolgen:

Code:
...main {
Klasse1 k1 = new Klasse1();
Klasse2 k2 = new Klasse2();

try {
k1.run();
}

catch (Exception e) {
[...]
k2.run();
[...]
}
}

Also würde ich persönlich das ganze per Exception Handling lösen...

Natürlich musst Du hierfür in Klasse1 diesen Konfliktfall per 'if' oder boolean als Exception hochwerfen. Es muss ja irgendeine Bedingung gelten, dass dieser Konfliktfall eintreten kann ;)
 
Zuletzt bearbeitet:
Tja, dann versuchs doch mal mit Threads. Starte einen Thread für deinen String den du generieren willst.. Dann schreibst du dir deine Exception und wenn diese Auftritt, rufst du im catch() Block deine Oberfläche auf, während du den momentanen Thread schlafen legst und zwar solange bis ein Button betätigt wurde in deiner Oberfläche (wie z.b. aus Killkrogs Lösung, was ich ähnlich programmiert hätte).

Mehr zu Threads: http://openbook.galileodesign.de/javainsel5/javainsel09_000.htm

Die Frage ist nur ob es an der Stelle nicht ein kompletter Overkill wäre. Aber die Frage darfst du dir selbst beantworten, TE. In meinen Augen ist das ein wenig wie mit den Kanonen und den Spatzen... Vielleicht ist meine Meinung auch dadurch begründet, dass ich (wir) nicht weiss (wissen) in welchen Ausmaßen sich dein Programm bewegt, wie komplex es ist, und alles was drum herum noch wichtig wäre zu wissen. Denn du musst immer den Unterschied zwischen einer simplen Primzahlberechnung und einem multithreaded Raytracer sehen.
 
Zuletzt bearbeitet:
Da kann ich dem Feuersturm nur zustimmen...
 
Hallo und danke für die vielen Antworten! Ich war die letzten Tage leider mit anderen, dringenderen Dingen beschäftigt, so dass ich mich erst jetzt wieder melde.

Das größte Problem hierbei war wohl eine fatale Fehlannahme meinerseits. Die einfache Lösung scheint wohl tatsächlich zu sein, den Dialog einfach modal zu machen. Jetzt verstehe ich auch, wo und warum Killkrogs Beispiel doch blockiert...

Code:
super(parent, "Choose!", [U]true[/U]);

Ich dachte bisher nämlich, dass ein modaler Dialog lediglich den Zugriff auf das Hauptfenster blockieren würde.

Jetzt habe ich nur noch ein kleines Problem: Ich habe den Code so geändert, dass der Dialog nicht mehr in einem eigenen Thread erzeugt wird, sondern direkt in der static-Methode.

Also:

Code:
    public static String showNameChooserDialog(String dirname) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            final NameChooser dialog = new NameChooser(new javax.swing.JFrame(), true, dirname);
            dialog.addWindowListener(new java.awt.event.WindowAdapter() {

                @Override
                public void windowClosing(java.awt.event.WindowEvent e) {
                    dialog.dispose();
                }
            });
            dialog.setVisible(true);
            return dialog.result;
        } // catch ...

        return null;
    }

anstatt mit

Code:
 public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                // selber Code hier
            }
        });
    }

Allerdings terminiert das Programm nun nicht mehr nach dem Aufruf der letzten Methode. Was muss ich dazu noch anpassen?
 
Zuletzt bearbeitet:
Feststellungen:

1. Ein Programm terminiert, wenn man System.exit() aufruft oder wenn alle Nicht-Daemon-Threads des Programms terminiert sind.

2. Sobald eine grafische Oberfläche erzeugt wird, erzeugt Java einen GUI-Thread, der zuständig dafür ist, diese Oberfläche zu kontrollieren (Mausklicks, Tastatureingaben, Oberfläche neu zeichnen, Events firen, etc...)

3. Der GUI-Thread terminiert erst dann, wenn es nichts mehr gibt, auf was er aufpassen könnte, das heisst, wenn wir alle grafischen Geschichten niedergemacht haben.


In deinem Fall, auch wenns ein bisschen schwer ist für nen Laien (was das Thema angeht) draufzukommen, ist, dass bei dir noch ein Fenster offen ist.
new NameChooser(new javax.swing.JFrame(), true, dirname);

Das JFrame ist der Schweinehund! Das existiert, auch wenn der JDialog geschlossen wird. Wenn du dir die API von JDialog mal genau ansiehst, wirst du feststellen, dass du anstatt nem JFrame als parent auch einfach null übergeben darfst. Dann erzeugt der JDialog intern ein eigenes JFrame und killt das gleich mit, wenn er selbst geschlossen wird. Damit sollte dein Programm dann auch terminieren. Wenn nicht, liegts wo anders, dann brauch ich mehr Code...
 
Doch, super, genau das war's! Danke! :)

Hab das eigentlich nur bei der Netbeans-Vorgabe belassen. Dass es auch mit null geht weiß ich, die unterschiedlichen Auswirkungen habe ich allerdings erst jetzt das erste Mal erlebt. Ohne das zu wissen hätte ich das Problem aber wohl nicht so schnell damit in Zusammenhang gebracht.

Was ich jetzt nur noch interessehalber gerne wüsste ist, wieso es auch mit new javax.swing.JFrame() funktioniert, wenn das ganze in einem eigenem Runnable-Objekt erfolgt bzw. was ein new javax.swing.JFrame() anstatt null als Vorgabe bringt.
 
Code:
public static void main(String[] args) {
	EventQueue.invokeLater(new Runnable() {

		public void run() {
			JDialog d = new JDialog(new JFrame(), "Titel", true);
			d.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
			d.setVisible(true);
		}
	});
}
Also, ein Programm mit dem Code terminiert nicht... Mit null dagegen schon. Passiert evtl noch irgendwas abgedrehtes in deiner NameChooser-Klasse?
 
Ah, ok. Liegt nicht an dem Runnable, sondern daran, dass ich die windowClosing-Methode angepasst habe. Hätte mich auch gewundert. Ich glaube damit ist alles erledigt, danke für die bemühte Hilfe! :)
 
Zurück
Oben