Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如果while循环为空,Swing程序不会关闭,但是如果while循环包含打印,Swing程序会关闭_Java_Swing - Fatal编程技术网

Java 如果while循环为空,Swing程序不会关闭,但是如果while循环包含打印,Swing程序会关闭

Java 如果while循环为空,Swing程序不会关闭,但是如果while循环包含打印,Swing程序会关闭,java,swing,Java,Swing,我在尝试使用swing(类似于JOptionPane)创建一个小对话框API时遇到了一个非常复杂的“bug” 基本上你调用一个方法,打开一个JFrame,等待一个按钮被选中并返回它;要等待按钮被选中,我使用while循环:while(isVisible()){}。现在wierd部分是,如果循环是空的(这里是空的),程序将不会完成,但是如果我在循环中放置System.out.print(),程序将完成。我试着在里面放些别的东西(比如inti=0;),但没有什么区别 编辑:即使没有打印和断点,使用调

我在尝试使用swing(类似于JOptionPane)创建一个小对话框API时遇到了一个非常复杂的“bug”

基本上你调用一个方法,打开一个JFrame,等待一个按钮被选中并返回它;要等待按钮被选中,我使用while循环:
while(isVisible()){}
。现在wierd部分是,如果循环是空的(这里是空的),程序将不会完成,但是如果我在循环中放置
System.out.print()
,程序将完成。我试着在里面放些别的东西(比如
inti=0;
),但没有什么区别

编辑:即使没有打印和断点,使用调试器也可以解决此问题

因为我不知道问题出在哪里,所以我将发布整个
对话框
类:

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);

几乎可以肯定的是,
while
循环在AWT事件调度线程(EDT)之外运行。使用
java.awt.EventQueue.invokeLater
进入正确的线程

如果您将Swing/AWT与多个线程一起使用(EDT将是一个线程,所以甚至不要使用主线程),那么您将遇到争用条件,并且会发生奇怪的事情。
System.out.println
通常会导致一些延迟,即使是单线程硬件,也会导致racy行为发生变化


在EDT上时,阻塞或运行忙循环将导致UI冻结。因此,您需要一个AWT/Swing事件处理程序将事件发送回您拥有的任何其他线程,或者启动一个新任务

我不知道为什么代码的行为不同,但解决方案是甚至不使用这两种代码。不要为这样的事情扩展JFrame。而是使用
模态JDialog
。模态JDialog会自动阻塞,直到对话框关闭。不需要特殊的逻辑。不要试图重新发明轮子。@camickr对不起,不是每个人都熟悉整个swing库,但是谢谢你的提示。这是一个有趣的观察,但不是一个好主意<代码>while(isVisible()){}将占用CPU并阻止,从而防止绘制窗口并阻止这些窗口响应用户输入。使用事件处理程序来检测组件状态的变化。UI不会冻结,它仍然会响应,即使dispose of The window仍然工作,循环也永远不会离开。为什么
System.out.print(“”)解决了这个问题?顺便说一句。我忘了提一下,但是使用调试器也可以解决它,即使没有打印。@VoroX嗯,首先你不应该使用
while(true)
循环,它不会冻结,因为代码没有在EDT上执行。纠正这个错误,它就会冻结我添加了一点要提到的是,
print
(或调试)会干扰计时。