如何用 JDialog 模仿 JPopupMenu 的行为?

Posted

技术标签:

【中文标题】如何用 JDialog 模仿 JPopupMenu 的行为?【英文标题】:How to mimic the behavior of JPopupMenu with JDialog? 【发布时间】:2022-01-23 05:34:59 【问题描述】:

我正在使用 Swing 实现“应用内”搜索引擎,我希望它的行为与 Windows 10 的搜索框完全相同。

搜索框应该:

在搜索按钮的上方和右侧打开,触摸按钮的边缘。 打开时有焦点。 按下搜索按钮即可关闭(如果打开)。 在搜索框外的任意位置用鼠标按下时关闭(如果打开)。

如果 JPopUpMenu 可以将 JDialog 作为它的子级,那就太完美了,但是因为我不需要从头开始实现这些行为(或者我需要吗?)。

这是我第一次使用 Swing,我很难自己实现所有内容。 我尝试在网上寻找示例,但找不到太多有用的信息。

对于 JPopUpMenu 无法托管 JDialog,是否有解决方法? 是否有实施我描述的行为的示例?

谢谢

================================编辑=============== ============== 感谢到目前为止的cmets。除了一个问题之外,我已经设法获得了我想要的行为。

以下代码创建一个带有按钮的框架:

public static void main(String[] args)
    
    JFrame mainWindow = new JFrame();
    mainWindow.setSize(420,420);
    mainWindow.setVisible(true);

    JFrame popUp = new JFrame();
    popUp.setSize(210, 210);

    JButton button = new JButton("button");
    mainWindow.add(button);

    button.addActionListener(new ActionListener() 
        @Override
        public void actionPerformed(ActionEvent e) 
            if(!button.isSelected())
                button.setSelected(true);
                popUp.setVisible(true);
            
            else
                button.setSelected(false);
                popUp.setVisible(false);
            
        
    );

    popUp.addWindowFocusListener(new WindowAdapter() 
        @Override
        public void windowLostFocus(WindowEvent e) 
            popUp.setVisible(false);
        
    );

当我点击按钮时,会出现一个弹出窗口,如果我点击主窗口外,弹出窗口会消失,但是当我想重新打开弹出窗口时,我需要按两次按钮。

当弹出窗口因失去焦点而关闭时,如何让按钮正常操作?

【问题讨论】:

您不能将 JDialog 添加到任何内容,因为它与操作系统本机对等窗口相关联。您可能想考虑使用 JWindow 来完成您想要完成的工作 不确定您的问题是什么。您可以轻松地使用所需的任何组件创建 JDialog。您向按钮添加逻辑以检查对话框是否可见,然后进行适当的处​​理。您将对话框设置为非模态对话框,以便在对话框可见时将焦点集中到对话框上的任何组件。您可以将 WindowListener 添加到对话框并处理 windowDeactivated 事件以关闭对话框。如果您需要更多帮助,请发帖 minimal reproducible example 展示您所做的工作,并一次提出一个具体问题。 JPopupMenu#setInvoker? 如果您想要 JDialogue 行为然后使用 JDialogue 并将其简单地定位在屏幕上 relative to your menu,或者如果您可以使用 yourPopup.insert(component, index); 将按钮或类似内容插入到您的 JPopupMenu 中并让按钮执行相关行动。 【参考方案1】:

您的“解决方案”非常脆弱。在左键单击JButton 之前尝试移动主JFrame

Oracle 有一个有用的教程,Creating a GUI With Swing。跳过 Netbeans 部分。学习本教程的其余部分。

我创建了一个主要的JFrame,它会弹出一个JDialog。我把关闭的JButton 放在JDialog 上。 JDialog 是模态的,这意味着当 JDialog 可见时,您无法访问主 JFrame

您可以将JDialog 放置在屏幕上您希望的任何位置。通常,您有一个JDialog 出现在父JFrame 的中心。这就是用户期望出现对话框的地方。我将JDialog 放在左上角,只是为了向您展示它是如何完成的。

这是完整的可运行代码。

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class PopupExample 

    public static void main(String[] args) 
        SwingUtilities.invokeLater(() -> new PopupExample().createAndShowGUI());
    

    private JFrame mainWindow;

    public void createAndShowGUI() 
        mainWindow = new JFrame("Main Window");
        mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        mainWindow.add(createMainPanel(), BorderLayout.CENTER);

        mainWindow.pack();
        mainWindow.setLocationByPlatform(true);
        mainWindow.setVisible(true);
    

    private JPanel createMainPanel() 
        JPanel panel = new JPanel(new FlowLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(200, 200, 200, 200));

        JButton button = new JButton("button");
        panel.add(button);

        button.addActionListener(new ActionListener() 
            @Override
            public void actionPerformed(ActionEvent e) 
                createAndShowDialog(mainWindow);
            
        );

        return panel;
    

    private void createAndShowDialog(JFrame frame) 
        JDialog dialog = new JDialog(frame, "Dialog", true);
        dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        dialog.add(createDialogPanel(dialog), BorderLayout.CENTER);

        dialog.pack();
        
        // Here's where you set the location of the JDialog relative
        // to the main JFrame
        Point origin = frame.getLocation();
        dialog.setLocation(new Point(origin.x + 30, origin.y + 30));
        
        dialog.setVisible(true);
    

    private JPanel createDialogPanel(JDialog dialog) 
        JPanel panel = new JPanel(new FlowLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));

        JButton button = new JButton("Close");
        panel.add(button);

        button.addActionListener(new ActionListener() 
            @Override
            public void actionPerformed(ActionEvent e) 
                dialog.dispose();
            
        );

        return panel;
    


【讨论】:

感谢您的回答,但我觉得我的问题没有被理解。我的问题(编辑后)是“如何创建一个在按下按钮时打开和关闭并在失去焦点时关闭的 JFrame?”

以上是关于如何用 JDialog 模仿 JPopupMenu 的行为?的主要内容,如果未能解决你的问题,请参考以下文章

如何用微信小程序模仿豆瓣首页

Swing组件中,如何用一个BUTTON弹出一个新窗口?

如何为扩展 JDialog 的类(或通常是另一个类)创建接口

在 World Wind 显示中获取 JPopupMenu

JTable与动态JPopupMenu

jpopupmenu menuitem actionperformed未触发