Программа Swing не закрывается, если цикл while пуст, однако закрывается, если цикл while содержит печать. - PullRequest
0 голосов
/ 10 июня 2019

Я столкнулся с очень странной «ошибкой» при попытке создания небольшого диалогового API с использованием Swing (аналогично JOptionPane).

Обычно вы вызываете метод, который открывает JFrame, ждет, пока кнопка не будет выбрана, и возвращает ее; чтобы дождаться выбора кнопки, я использую цикл while: while (isVisible()) {}. Теперь странным моментом является то, что программа не завершится, если цикл будет пустым (как здесь), однако, если я поместу System.out.print() внутри, он будет. Я пытался поместить что-то еще внутри (например, int i = 0;), но это не имеет значения.

РЕДАКТИРОВАТЬ: использование отладчика решает эту проблему даже без печати и без точек останова.

Поскольку я понятия не имею, в чем может быть проблема, я выложу весь класс Dialog:

package Frame.Dialogs;

import GameEngine.EngineMgr;

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

public class Dialog extends JFrame {

public enum Buttons {
    OK(Dialog.OK),
    YES(Dialog.YES),
    RETURN(Dialog.RETURN),
    CONFIRM(Dialog.CONFIRM),
    YES_NO(Dialog.YES, Dialog.NO),
    YES_NO_CANCEL(Dialog.YES, Dialog.NO, Dialog.CANCEL),
    YES_CANCEL(Dialog.YES, Dialog.CANCEL),
    YES_RETURN(Dialog.YES, Dialog.RETURN),
    OK_CANCEL(Dialog.OK, Dialog.CANCEL),
    CONFIRM_CANCEL(Dialog.CONFIRM, Dialog.CANCEL),
    CONFIRM_RETURN(Dialog.CONFIRM, Dialog.RETURN);

    private JButton[] buttons;

    Buttons(JButton... buttons) {
        this.buttons = buttons;
    }

    JButton[] val() {
        return buttons;
    }
}

public static final JButton OK = new JButton("OK");
public static final JButton NO = new JButton("NO");
public static final JButton YES = new JButton("YES");
public static final JButton CANCEL = new JButton("CANCEL");
public static final JButton RETURN = new JButton("RETURN");
public static final JButton CONFIRM = new JButton("CONFIRM");

private static boolean initialized = false;

private JPanel button;
private JPanel content;
private JButton selection;

private Dialog(JPanel panel, String title, Buttons buttons) {
    if (!initialized)
        initialize();

    setTitle(title);
    setIconImage(null);

    button = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
    for (JButton b : buttons.val())
        button.add(b);

    content = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
    content.add(panel);
}

@SuppressWarnings("StatementWithEmptyBody")
private JButton display() {
    setLayout(new GridBagLayout());
    setBackground(Color.BLACK);

    GridBagConstraints c1 = new GridBagConstraints();
    c1.fill = GridBagConstraints.BOTH;
    c1.gridx = 0;
    c1.gridy = 0;
    c1.insets = new Insets(10, 10, 10, 10);
    GridBagConstraints c2 = (GridBagConstraints) c1.clone();
    c2.gridy = 1;

    add(content, c1);
    add(button, c2);
    pack();
    Dimension sc = Toolkit.getDefaultToolkit().getScreenSize();
    setLocation((sc.width - getWidth()) / 2, (sc.height - getHeight()) / 2);
    setVisible(true);

    //Strange loop

    //Will get stuck:
    //while (isVisible()) {}

    //Works fine:
    while (isVisible())
        System.out.print("");

    return selection;
}

private void initialize() {
    //JButton[] buttons = new JButton[]{YES, NO, OK, CANCEL, RETURN, CONFIRM};
    JButton[] buttons = new JButton[]{OK};
    for (JButton b : buttons) {
        b.setBorder(BorderFactory.createEmptyBorder());
        b.setContentAreaFilled(false);
        b.setIcon(new ImageIcon(EngineMgr.getGraphicEngine().get("bt_" + b.getText()).getScaledInstance(150, 84, Image.SCALE_SMOOTH)));
        b.setSelectedIcon(new ImageIcon(EngineMgr.getGraphicEngine().get("sBt_" + b.getText()).getScaledInstance(150, 84, Image.SCALE_SMOOTH)));
        b.setPressedIcon(new ImageIcon(EngineMgr.getGraphicEngine().get("pBt_" + b.getText()).getScaledInstance(150, 84, Image.SCALE_SMOOTH)));
        b.setText("");
        b.setSize(new Dimension(150, 50));
        b.addActionListener(e -> {
            selection = b;
            dispose();
        });
    }
}

public static JButton showDialog(String msg, String title, Buttons buttons) {
    JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
    panel.add(new JLabel(msg));
    return new Dialog(panel, title, buttons).display();
}

public static JButton showDialog(JPanel panel, String title, Buttons buttons) {
    return new Dialog(panel, title, buttons).display();
}

}

Также вот звонок:

JButton selection = Dialog.showDialog("Test 1", "Test", Dialog.Buttons.OK);
if (selection == Dialog.OK)
    System.out.println("OK");
System.exit(0);

1 Ответ

1 голос
/ 11 июня 2019

Вы почти наверняка имеете цикл while, работающий вне потока обработки событий AWT (EDT).Используйте java.awt.EventQueue.invokeLater, чтобы перейти к правильному потоку.

Если вы используете Swing / AWT с несколькими потоками (EDT будет одним потоком - так что даже не используйте основной поток), тогда вы будетеесть условия гонки и странные вещи произойдут.Обычно System.out.println вызывает некоторую задержку, даже при использовании однопоточного оборудования, что приводит к изменению нестабильного поведения.

Когда на EDT блокировка или выполнение занятого цикла приведет к зависанию пользовательского интерфейса.Поэтому вам понадобится обработчик событий AWT / Swing, чтобы отправить событие обратно в любой другой поток или запустить новую задачу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...