当整个应用程序在打开之前失去焦点时,Java模态对话框会冻结整个应用程序

当整个应用程序在打开之前失去焦点时,Java模态对话框会冻结整个应用程序,java,swing,modal-dialog,freeze,Java,Swing,Modal Dialog,Freeze,执行以下步骤后,整个应用程序将被冻结,模式对话框将无法关闭 (这与此相关,但这次我们有一个可复制的场景) 步骤如下: 开放式下拉列表 选择“Han Ra”(下拉列表中的最后一个值) 在此之后,尝试调整或关闭模式对话框将不会成功。它会复制三次中的一次(如果通过向下箭头选择,可能更容易复制,但也会使用鼠标选择) 这种情况发生在jdk1.8(试用1.8.0_162和1.8.0_144)和jdk 10(10.0.1)上,但在使用1.7(试用1.7.0_80) 这只是我们能找到的最明显的例子,但它在大

执行以下步骤后,整个应用程序将被冻结,模式对话框将无法关闭

(这与此相关,但这次我们有一个可复制的场景)

步骤如下:

  • 开放式下拉列表
  • 选择“Han Ra”(下拉列表中的最后一个值)
在此之后,尝试调整或关闭模式对话框将不会成功。它会复制三次中的一次(如果通过向下箭头选择,可能更容易复制,但也会使用鼠标选择)

这种情况发生在jdk
1.8
(试用
1.8.0_162
1.8.0_144
)和
jdk 10
10.0.1
)上,但在使用
1.7
(试用
1.7.0_80

这只是我们能找到的最明显的例子,但它在大多数模态对话框中随机(很少)发生。 还有谁有这个问题并找到了解决办法?我们将向Oracle报告,但我们更感兴趣的是解决方案

import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

public class FreezePleeze {

    public static final Object[] ALL_THE_SINGLE_LADIES = {"Rahan", "Crao", "Naouna", "Han-ra"};

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

    public FreezePleeze() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JButton push_me = new JButton("Push me");
                JFrame frame = new JFrame("Mmmmm");
                JPanel containerPanel = new JPanel();
                frame.add(containerPanel);
                final JComboBox<Object> comboBox = new JComboBox<>(ALL_THE_SINGLE_LADIES);
                containerPanel.add(comboBox);
                frame.setSize(300, 300);

                comboBox.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        JDialog jDialog = new JDialog((JFrame) null, true);
                        jDialog.add(push_me);
                        if (comboBox.getSelectedIndex() == ALL_THE_SINGLE_LADIES.length - 1) {
                            jDialog.setLocationRelativeTo(frame);
                            jDialog.setSize(300, 300);
                            jDialog.setVisible(true);
                        }
                    }
                });

                comboBox.addPopupMenuListener(new PopupMenuListener() {
                    @Override
                    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                    }

                    @Override
                    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                        try {
                            Robot robot = new Robot();
                            robot.keyPress(KeyEvent.VK_WINDOWS);
                            robot.keyRelease(KeyEvent.VK_WINDOWS);
                        } catch (AWTException e1) {
                            e1.printStackTrace();
                        }
                        push_me.setText("Finished counting");
                    }

                    @Override
                    public void popupMenuCanceled(PopupMenuEvent e) {
                    }
                });
                frame.setVisible(true);
            }
        });
    }
}
import javax.swing.*;
导入javax.swing.event.PopupMenuEvent;
导入javax.swing.event.PopupMenuListener;
导入java.awt.*;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.KeyEvent;
公开课{
公共静态最终对象[]所有单身女士={“Rahan”、“Crao”、“Naouna”、“Han-ra”};
公共静态void main(字符串[]args){
新的冷冻钳();
}
公共图书馆({
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
JButton push_me=新JButton(“push me”);
JFrame=新JFrame(“Mmmmm”);
JPanel containerPanel=新的JPanel();
添加框架(容器面板);
最终JComboBox组合框=新JComboBox(所有单身女士);
containerPanel.add(组合框);
框架。设置尺寸(300300);
comboBox.addActionListener(新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
JDialog JDialog=newjdialog((JFrame)null,true);
jDialog.add(推送我);
if(comboBox.getSelectedIndex()==ALL\u THE\u SINGLE\u LADIES.length-1){
jDialog.setLocationRelativeTo(帧);
jDialog.setSize(300300);
jDialog.setVisible(true);
}
}
});
comboBox.addPopupMenuListener(新的PopupMenuListener(){
@凌驾
public void弹出菜单将变为可见(弹出菜单事件e){
}
@凌驾
public void PopupMenu将变得不可见(PopupMenuEvent e){
试一试{
机器人=新机器人();
robot.keyPress(KeyEvent.VK_窗口);
robot.keyrease(KeyEvent.VK_窗口);
}捕获(AWTEXE1){
e1.printStackTrace();
}
按我的设置(“完成计数”);
}
@凌驾
公共无效popupMenuCanceled(PopupMenuEvent e){
}
});
frame.setVisible(true);
}
});
}
}

我可以重现您的问题。解决方案是将正确的窗口提交给对话框的构造函数:

例如:

JDialog jDialog = new JDialog(frame, true);
或者,如果创建对话框时没有窗口实例:

JDialog jDialog = new JDialog(FocusManager.getCurrentKeyboardFocusManager().getActiveWindow(),
                            ModalityType.APPLICATION_MODAL);

您正在使用长时间运行的操作阻止事件调度线程…不确定您在做什么expecting@MadProgrammer-问题不是UI等待长时间操作运行。问题是,在运行代码后,UI变得无响应,模式对话框无法关闭。“问题不是UI等待长时间操作运行”,问题恰恰是“长时间操作运行”。删除它或使用SwingWorker,如中所示,gui将保持完全响应。@c0der-我们花了很多时间(1-2个月)才找到解决此问题的方案。这就是为什么一开始我使用长时间运行的操作,因为我认为这是必要的。我认为现在这个问题已经很清楚,也很容易重现,但看起来解决起来并不容易。这里是JDK的问题,以防其他人想要遵循好的捕获。了解这一点很有用,但这是一种解决方法,而不是解决方案。完成此操作后,下拉列表保持打开状态,非常奇怪的是,它在下一个焦点丢失事件中关闭。我希望它在打开或关闭模式对话框时关闭。@VladTopala您只需调用comboBox.hidePopup();在创建对话框之前。是的,但仍然是一种解决方法。在整个应用程序中有不同的侦听器,对于随机对话框,它会冻结。