Java auf Button-Eingabe warten lassen?
In meinem Java-Programm wird an einer Stelle ein neuer JDialog erstellt und ich möchte, dass die Klasse, über die den Dialog aufgerufen wird, solange wartet, bis in dem Dialog ein Button angeklickt wird.
Methode der Klasse Spiel:
public boolean handeln(Spieler aktuellerSpieler, Spieler Partner) {
if (aktuellerSpieler == Partner) {
JOptionPane.showMessageDialog(Spiel.this, "Sie können nicht mit sich selber handeln!", "FEHLER", JOptionPane.WARNING_MESSAGE);
return false;
}
setVisible(false);
Handel dialog = new Handel(aktuellerSpieler, Partner, Spiel.this);
// Warte auf Button Eingabe in dialog
return true;
}
Code der Dialog-Klasse:
public Handel(Spieler player1, Spieler player2, Spiel Instanz) {
setVisible(true);
setBounds(100, 100, 1030, 471);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(null);
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("BESTÄTIGEN!");
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
{
JButton cancelButton = new JButton("Exit");
buttonPane.add(cancelButton);
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Handel.this.dispose();
Instanz.setVisible(true);
// Auf diesen Button soll gewartet werden.
}
});
}
}
}
1 Antwort
Zuerst:
1) Schmeiße diese Zeile raus und vergiss diese Methodik auch schnell wieder, denn sie stellt derb schlechten Stil dar.
contentPanel.setLayout(null);
Verwende einen regulären Layout Manager oder falls du damit nicht zurechtkommst, gibt es noch externe Bibliotheken (MiGLayout) oder den Swing Builder (wie WindowBuilder) für Drag&Drop.
Am besten wäre es zudem auch, die Größe des Fensters automatisch mit pack ermitteln zu lassen. Gewünschte Größen kann man mit setPreferredSize anbringen.
2) Wenn ich einmal davon ausgehe, dass du für deinen Dialog entweder einen JFrame oder JDialog verwendest, ist der Standard-Layout-Manager bereits das BorderLayout. Das heißt, diese Zeile:
getContentPane().setLayout(new BorderLayout());
kann auch raus.
3) Der Zugriff auf das ContentPane lässt sich leicht über this abkürzen. Du brauchst es nicht explizit holen, das macht die JFrame/JDialog-Klasse schon für dich.
4) Mache dein Fenster erst sichtbar, sobald es auch fertig ist (also alle gewünschten Komponenten angehängt und Größen, Position, etc. festgelegt wurden). Andernfalls zwingst du Swing dazu, das Fenster mehrmals (und unnötig) nacheinander neuzeichnen zu lassen.
5) Ich verstehe nicht, wieso du so viele Code-Blöcke öffnest. Soll das deine Art an Code-Strukturierung sein? Um Quellcode in übersichtliche Blöcke aufzuteilen, gibt es in Java Methoden.
Zu deinem Problem:
Erweitere eine JDialog-Klasse, die als Modal gekennzeichnet wird. Sie hält ein Feld, welches den Rückgabewert speichert und zudem wird in ihr eine Methode definiert, die zum einen das Fenster einblendet und zum anderen den erwarteten Wert zurückgibt. Die Action Listener der Buttons in diesem Fenster sorgen für eine Berechnung des Rückgabewerts und das folgende Ausblenden des Dialogs.
Dazu ein einfaches Beispiel:
Main.java
import java.awt.*;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Modal dialog example");
frame.setLayout(new FlowLayout());
final JLabel label = new JLabel();
JButton askButton = new JButton("Open modal");
askButton.addActionListener(evt -> {
var dialog = new MyDialog(frame);
label.setText(dialog.showModal());
});
frame.add(askButton);
frame.add(label);
frame.pack();
frame.setVisible(true);
});
}
}
MyDialog.java
import java.awt.*;
import javax.swing.*;
public class MyDialog extends JDialog {
private String result;
public MyDialog(Window parent) {
super(parent, ModalityType.APPLICATION_MODAL);
setLayout(new FlowLayout());
JButton okButton = new JButton("OK");
okButton.addActionListener(evt -> {
result = "Approved.";
dispose();
});
add(okButton);
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(evt -> {
result = "Cancelled.";
dispose();
});
add(cancelButton);
pack();
}
public String showModal() {
setVisible(true);
return result;
}
}
An sich könnte man diese Klasse noch weiter abstrahieren, indem man den Rückgabetyp generisch definiert und die Berechnung ebenso in eine eigene Klasse auslagert (siehe Strategy Pattern).
Weitere Informationen zu Dialogen und Modals findest übrigens du in der Oracle Dokumentation:
Zu 1) - 3) ich erstelle die GUI über den Eclipse Editor und der hat das wohl an den Stellen so gemacht.