【问题标题】:How to show JOptionPane above modeless JDialog如何在无模式 JDialog 上方显示 JOptionPane
【发布时间】:2019-10-19 17:17:50
【问题描述】:

我希望 JOptionPane 出现在无模式对话框上方。例如,在以下应用程序中,请按JDialog 按钮显示无模式对话框,然后按JOptionPane 按钮显示JOptionPane 确认对话框。不幸的是,JOptionPane 出现在无模式对话框下。

在我的真实应用程序中,我有几个无模式的 JDialog,我从几个不同的地方使用 JOptionPane。

我如何轻松让 JOptionPane 出现在所有无模式的 JDialog 实例之上? “轻松”是指在每个无模式 JDialog 构造或每个 JOptionPane 调用中添加 1 或 2 行。

我尝试的一种方法是创建一个新的临时无主 JFrame,它具有始终位于顶部的选项作为 JOptionPane 的所有者。这使得 JOptionPane 位于顶部,但 JOptionPane 位于屏幕中心而不是原始 JFrame 的中心,我担心用户可能不会注意到它。

我尝试的另一种方法是在显示 JOptionPane 之前让所有无模式对话框不可见,然后再让它们再次可见。但是这种方式并不容易对 JOptionPane 进行所有调用,因为(我相信)它需要一个 try-finally 块才能可靠地执行。

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

public class App {
    public static void main(String[] args) {
        JFrame f = new JFrame("App Frame");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton btnDialog = new JButton("JDialog");
        JButton btnOptionPane = new JButton("JOptionPane");

        btnDialog.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JDialog dlg = new JDialog(f, "Modeless Dialog", false);
                dlg.setSize(256, 256);
                dlg.setLocationRelativeTo(f);
                dlg.setVisible(true);
            }
        });

        btnOptionPane.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showConfirmDialog(f, "Confirm JOptionPane");
            }
        });

        f.add(btnDialog, BorderLayout.WEST);
        f.add(btnOptionPane, BorderLayout.EAST);
        f.setSize(512, 512);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

【问题讨论】:

    标签: java swing


    【解决方案1】:

    您需要为选项窗格设置正确的父级。要确定它,您可以使用所有打开的窗口的列表。在我的示例中,我使用最后打开的窗口。

    import java.awt.BorderLayout;
    import java.awt.Window;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.JButton;
    import javax.swing.JDialog;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    
    public class App {
    
        public static void main(String[] args) {
            JFrame f = new JFrame("App Frame");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JButton btnDialog = new JButton("JDialog");
            JButton btnOptionPane = new JButton("JOptionPane");
    
            btnDialog.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JDialog dlg = new JDialog(f, "Modeless Dialog", false);
                    dlg.setSize(256, 256);
                    dlg.setLocationRelativeTo(f);
                    dlg.setVisible(true);
                }
            });
    
            btnOptionPane.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JOptionPane.showConfirmDialog(findLatestWindow(), "Confirm JOptionPane");
                }
            });
    
            f.add(btnDialog, BorderLayout.WEST);
            f.add(btnOptionPane, BorderLayout.EAST);
            f.setSize(512, 512);
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
        private static Window findLatestWindow() {
            Window result = null;
            for (Window w : Window.getWindows()) {
                if (w.isVisible()) {
                    result = w;
                }
            }
            return result;
        }
    }
    

    如果您同时打开了多个对话框,并且用户可以在这些对话框之间切换,那么您需要更多的代码行。因为在您的情况下,单击按钮后框架始终是焦点所有者。

    【讨论】:

    • 感谢谢尔吉的评论。然而,在我的真实应用程序中,我有几个无模式对话框和几个对 JOptionPane 的调用,而 JOptionPane 只接受一个所有者窗口。我刚刚用这个附加要求编辑了我的问题。抱歉,在您回答之前我没有提及。
    • @AdamGawne-Cain 我已经改变了一点我的答案。可能这会对你有所帮助。如果您需要更复杂的解决方案,请告诉我(查找最新的活动对话框)。
    • 好主意,但它在 OSX 中对我不起作用:JOptionPane 位于某些对话框之上,但位于其他对话框之下。我猜 Window.getWindows() 中的 Windows 顺序在所有平台上都不是很有意义(例如桌面 Z 顺序)。
    【解决方案2】:

    在尝试并尝试了@Sergiy 使用静态窗口方法的想法后,我想出了这个:

    import java.awt.BorderLayout;
    import java.awt.Window;
    import java.awt.event.*;
    import java.util.ArrayList;
    
    import javax.swing.*;
    
    public class App {
        static JFrame hideOwnedWindows(JFrame f) {
            ArrayList<Window> arHidden = new ArrayList();
            WindowAdapter wa = new WindowAdapter() {
                @Override
                public void windowActivated(WindowEvent e) {
                    for (Window w : arHidden)
                        w.setVisible(true);
                    f.removeWindowListener(this);
                }
            };
            for (Window w : f.getOwnedWindows()) {
                if (w.isVisible()) {
                    w.setVisible(false);
                    arHidden.add(w);
                }
            }
            f.addWindowListener(wa);
            return f;
        }
    
        public static void main(String[] args) {
            JFrame f = new JFrame("App Frame");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JButton btnDialog = new JButton("JDialog");
            JButton btnOptionPane = new JButton("JOptionPane");
    
            btnDialog.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    JDialog dlg = new JDialog(f, "Modeless Dialog", false);
                    dlg.setSize(256, 256);
                    dlg.setLocationRelativeTo(f);
                    dlg.setVisible(true);
                }
            });
    
            btnOptionPane.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    JOptionPane.showConfirmDialog(hideOwnedWindows(f), "Confirm JOptionPane");
                }
            });
    
            f.add(btnDialog, BorderLayout.WEST);
            f.add(btnOptionPane, BorderLayout.EAST);
            f.setSize(512, 512);
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
    }
    

    “hideOwnedWindows”方法隐藏所有拥有的窗口,包括对话框,然后在下次激活主 JFrame 时恢复它们。由于在 JOptionPane 期间所有拥有的 Windows 都是不可见的,我认为(希望)当 JOptionPane 关闭时,主 JFrame 总是被激活。

    【讨论】:

    • 很好的工作方法,我建议创建一个方法来打开一个JOptionPane,它会调用你的hideOwnedWindows,这样你就不必到处调用JOptionPane.showConfirmDialog(hideOwnedWindows(f),只需一个openJOptionPane(params)
    猜你喜欢
    • 1970-01-01
    • 2012-03-08
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 2019-05-02
    • 2014-02-11
    • 2023-03-12
    • 2015-04-22
    相关资源
    最近更新 更多