2011-06-03 88 views
5

有右键关联菜单的一些性质,我想用JPopupMenu的复制:如何防止通过点击外部关闭JPopupMenu时触发其他事件?

  1. 当菜单打开并单击其他地方,菜单关闭。
  2. 当菜单打开并在其他地方点击时,没有其他事情发生。

我已经把第一部分弄好了。但是当我点击其他地方时,可能会发生其他事件。例如,假设我有按钮A,它执行一些操作B.目前,如果JPopupMenu已打开,并且我单击A,则JPopupMenu关闭并执行B.我宁愿JPopupMenu关闭和B不执行。这可能吗?

感谢

+1

我不明白为什么你不想让按钮触发事件,当用户在其上点击,但每当JPopupMenu事件被触发,禁用按钮单击事件,然后在菜单关闭时重新启用事件。 – 2011-06-03 17:22:20

+0

@BCarpe,这是“check-then-act”的简单例子吗?在打开'JPopupMenu'时设置一个标志,然后在你的'actionPerformed'方法中检查只有在没有设置标志时才会执行它们的例程。 – mre 2011-06-03 17:32:02

+0

这只是约定。自己尝试一下。右键单击您的浏览器,然后单击任何地方。它总是先关闭,然后让你点击其他任何东西。至于禁用/重新启用,我有很多组件,可能会增加更多,所以跟踪该机制会增加一点复杂性,比我真正处理。 – BCarpe 2011-06-03 17:33:34

回答

3

考虑到什么是你的问题和评论说,我会在下面的方法之一来解决你的问题。

从技术上讲,你这里有两种选择:

1.Hide每当用户移动鼠标在弹出的外弹出。这样你就没有用户点击的问题,因为弹出窗口本身就会消失。

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(...)提供。您可以对该行进行注释,并观察该行为在任何情况下都会在您目前遇到的情况下发生。

+0

谢谢!是的,全球性的听众正是我所期待的。 – BCarpe 2011-06-09 14:51:48

11

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

UIManager.put("PopupMenu.consumeEventOnClose", Boolean.TRUE); 

这也是值得一提的这只消耗MOUSE_PRESSED事件,不消耗随后MOUSE_CLICKED事件。您可以通过在mousePressed()中设置标志并在mouseReleased()中测试它来模拟鼠标。如果按下鼠标最初被消耗,则标志将不会在的mouseReleased()设置

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; 
} 
+0

+1,我不知道这个事实。这太神奇了:-) – 2012-03-10 11:38:46

+0

这对我来说是非常有用的,可以禁用这种行为:)当随后的右键单击时,弹出式菜单已经打开,显示新菜单但未选择该行,导致出现问题。 – 2014-05-12 01:28:44

+0

我有完全相反的问题。当我检查它时,这个值是真的,所以我将它设置为false(并且仔细检查它保持为false),但是我的事件仍然被消耗。 – 2015-07-14 10:25:10

相关问题