Java 如何在关闭JPopupMenu时通过单击其外部来防止触发其他事件?

Java 如何在关闭JPopupMenu时通过单击其外部来防止触发其他事件?,java,swing,menu,jpopupmenu,Java,Swing,Menu,Jpopupmenu,我想用JPopupMenu复制右键单击上下文菜单的一些属性: 当菜单打开并单击其他位置时,菜单关闭 当菜单打开并单击其他位置时,不会发生任何其他情况 我把第一部分写得很好。但当我点击其他地方时,其他事件可能会发生。例如,假设我有一个按钮A,它执行一些动作B。当前,如果JPOPUP菜单打开,我单击A,JPOPUP菜单关闭,B被执行。我希望JPOPUPMENUS关闭,并且不执行B。这可能吗 谢谢考虑到您在问题和评论中所说的内容,我将用以下方法之一解决您的问题 从技术上讲,您有两种选择: 1.每当用户

我想用JPopupMenu复制右键单击上下文菜单的一些属性:

  • 当菜单打开并单击其他位置时,菜单关闭
  • 当菜单打开并单击其他位置时,不会发生任何其他情况 我把第一部分写得很好。但当我点击其他地方时,其他事件可能会发生。例如,假设我有一个按钮A,它执行一些动作B。当前,如果JPOPUP菜单打开,我单击A,JPOPUP菜单关闭,B被执行。我希望JPOPUPMENUS关闭,并且不执行B。这可能吗


    谢谢

    考虑到您在问题和评论中所说的内容,我将用以下方法之一解决您的问题

    从技术上讲,您有两种选择:

    1.每当用户将鼠标移到弹出窗口外时,隐藏弹出窗口。这样你就不会有用户点击的问题,因为弹出窗口会自动消失

    2.全局捕获此特定鼠标事件,如果弹出窗口可见,则在左键单击时使用该事件。我在下面的例子中展示了这个特殊的解决方案

        import java.awt.AWTEvent;
        import java.awt.Toolkit;
        import java.awt.event.AWTEventListener;
        import java.awt.event.ActionEvent;
        import java.awt.event.MouseAdapter;
        import java.awt.event.MouseEvent;
        import javax.swing.AbstractAction;
        import javax.swing.JButton;
        import javax.swing.JFrame;
        import javax.swing.JMenu;
        import javax.swing.JPanel;
        import javax.swing.JPopupMenu;
        import javax.swing.SwingUtilities;
    
        public class DisableClickWhenPopupVisibleTest
        {
            public static void main(String[] args)
            {
                SwingUtilities.invokeLater(new Runnable()
                {
                    @Override
                    public void run()
                    {               
                        final JPopupMenu popup = new JPopupMenu();
                        popup.add(new JMenu("aAaa"));
                        JPanel contentPane = new JPanel();
                        contentPane.add(popup);
                        JButton b = new JButton();
                        b.setAction(new AbstractAction("Button")
                        {
                            private static final long serialVersionUID = 1L;
                            @Override
                            public void actionPerformed(ActionEvent e)
                            {
                                System.out.println("b actionPerformed");
                            }
                        });
                        contentPane.add(b);
                        contentPane.addMouseListener(new MouseAdapter() {
                            @Override
                            public void mousePressed(MouseEvent e)
                            {
                                showPopup(e);
                            }
                            @Override
                            public void mouseReleased(MouseEvent e)
                            {
                                showPopup(e);
                            }
                            private void showPopup(MouseEvent e)
                            {
                                if(e.isPopupTrigger())
                                    popup.show(e.getComponent(), e.getX(), e.getY());
                            }
                        });
                        //use global mouse event capture to disable left click on anything when popup is visible
                        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
                            @Override
                            public void eventDispatched(AWTEvent event)
                            {
                                MouseEvent me = (MouseEvent)event;
                                if(me.getID() == MouseEvent.MOUSE_PRESSED)
                                {
                                    System.out.println("eventDispatched popup.vis="+popup.isVisible());
                                    if( me.getButton() == MouseEvent.BUTTON3)
                                    {   
                                        System.out.println("BUTTON3");
                                    }   
                                    else if(me.getButton() == MouseEvent.BUTTON1)
                                    {
                                        System.out.println("BUTTON1");
                                        if(popup.isVisible())
                                            me.consume();
                                    }
                                }
                            }
                        }, AWTEvent.MOUSE_EVENT_MASK);                      
                        JFrame f = new JFrame();
                        f.setContentPane(contentPane);
                        f.setSize(400, 300);
                        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                        f.setVisible(true);
                    }
                });
            }
        }
    

    您可以通过右键单击按钮左侧来测试该示例,然后弹出窗口将显示。然后,如果单击按钮,则不会调用其操作。如果弹出窗口被隐藏,则通常会调用该操作。此功能由以下代码行
    Toolkit.getDefaultToolkit().addAWTEventListener(…)
    提供。您可以注释掉该行,并观察到该操作将在您当前体验的任何情况下发生。

    这是有效的,而且简单得多。。。虽然可以被一些外观和感觉所覆盖

    UIManager.put("PopupMenu.consumeEventOnClose", Boolean.TRUE);
    
    还值得注意的是,这只会消耗鼠标按下事件,而不会消耗后续的鼠标点击事件。您可以通过在mousePressed()中设置标志并在mouseReleased()中测试来模拟单击的鼠标。如果最初按下的鼠标已被使用,则不会在mouseReleased()中设置该标志


    我不明白为什么您不希望在用户单击按钮事件时触发该事件,但每当触发JPopupMenu事件时,请禁用按钮单击事件,然后在菜单关闭时重新启用该事件。@BCarpe,这是“检查然后执行”的简单情况吗?在打开
    jpopmpmenu
    时设置一个标志,然后在
    actionPerformed
    方法中进行检查,该方法仅在未设置标志的情况下执行例行程序。这只是惯例。你自己试试看。在浏览器上单击鼠标右键,然后单击任意位置。它总是先关闭,然后再让您单击任何其他内容。至于禁用/重新启用,我有很多组件,并且可能会添加更多,因此跟踪该机制将增加比我实际能够处理的更复杂的一点。@mre,我真的不想在每个组件中加入处理这种情况的方法。关闭时是否有JPOppMenu发出的信号--编辑--PopupMenuListener执行此操作。@BCarpe如果我在浏览器中单击鼠标右键,然后单击与我所在选项卡不同的选项卡,它将选择新选项卡。(Chrome)谢谢!是的,globals侦听器正是我想要的。禁用此行为对我很有用:)当弹出菜单已经打开时,它会导致后续右键单击出现问题,显示新菜单但不选择行。我的问题正好相反。当我检查该值时,该值为true,因此我将其设置为false(并再次检查它是否保持false),但我的事件仍然被消耗。
    private boolean pressed = false;
    
    @Override
    public void mousePressed(MouseEvent e) {
        pressed = true;
    }
    
    @Override
    public void mouseReleased(MouseEvent e) {
        if (pressed) {
             // do click stuff
        }
        pressed = false;
    }