Как предотвратить запуск других событий при закрытии JPopupMenu, нажав за его пределами? - PullRequest
5 голосов
/ 03 июня 2011

Есть некоторые свойства контекстного меню, вызываемого правой кнопкой мыши, которое я хотел бы скопировать с помощью JPopupMenu:

  1. Когда меню открыто и вы щелкаете в другом месте, меню закрывается.
  2. Когда меню открыто и вы щелкаете в другом месте, больше ничего не происходит.

У меня первая часть просто в порядке. Но когда я нажимаю в другом месте, могут происходить другие события. Например, допустим, у меня есть кнопка A, которая выполняет некоторое действие B. В настоящее время, если JPopupMenu открыто, и я нажимаю A, JPopupMenu закрывается и выполняется B. Я бы предпочел, чтобы JPopupMenu закрылся и B НЕ выполнялся. Возможно ли это?

Спасибо

Ответы [ 2 ]

11 голосов
/ 28 сентября 2011

Это работает, и намного проще ... хотя может быть переопределено некоторым видом и ощущениями.

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;
}
3 голосов
/ 07 июня 2011

Принимая во внимание то, что было сказано в вашем вопросе и комментариях, я подхожу к вашей проблеме одним из следующих способов.

Технически у вас есть два варианта:

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(...). Вы можете закомментировать строку и заметить, что тогда действие будет происходить в любом случае, как вы испытываете его в настоящее время.

...