2013-10-24 2 views
0

У меня есть JPopupMenu, который содержит внутренний JMenu и разделитель с addSeparator(). Из-за некоторой нечетной обработки я добавил MouseListener в JPopupMenu, что делает его невидимым на мероприятии mouseExited. Это прекрасно работает, за исключением того, что, когда мышь пытается пересечь разделитель, он запускает событие (хотя является суперкомпонентом).Триггеры события MouseExited при пересечении внутреннего разделителя?

Если я удаляю линию addSeparator(), она работает должным образом.

Есть ли способ обойти это? Или я не правильно настроил слушателя?

код похож на следующее:

JPopupMenu popupMenu = new JPopupMenu(); 
JMenu innerMenu = new JMenu("Inner"); 
// ... add JMenuItems 
popupMenu.add(innerMenu); 
popupMenu.addSeparator(); 
popupMenu.add(new JMenuItem("Exit")); 

popupMenu.addMouseListener(new MouseAdapter() { 
    @Override 
    public void mouseExited(MouseEvent e) { 
     popupMenu.setVisible(false); 
    } 
}); 

Полный компилируется Пример

Просто комментировать и раскомментироватьpopupMenu.addSeparator()линии замечать различные модели поведения

public class Test { 


    public static void main(String[] args) throws Exception { 
     if(!SystemTray.isSupported()) { 
      throw new UnsupportedOperationException("SystemTray is not supported."); 
     } 

     final TrayIcon trayIcon = new TrayIcon(ImageIO.read(new File("resources/icon.gif"))); 
     final JPopupMenu popupMenu = new JPopupMenu(); 
     JMenu intervalMenu = new JMenu("Interval"); 
     ButtonGroup itemGroup = new ButtonGroup(); 

     JRadioButtonMenuItem oneSecondMenuItem = new JRadioButtonMenuItem("1 sec"); 
     itemGroup.add(oneSecondMenuItem); 
     JRadioButtonMenuItem twoSecondMenuItem = new JRadioButtonMenuItem("2 sec"); 
     itemGroup.add(twoSecondMenuItem); 

     intervalMenu.add(oneSecondMenuItem); 
     intervalMenu.add(twoSecondMenuItem); 

     popupMenu.add(intervalMenu); 

     popupMenu.addSeparator(); 

     JMenuItem exitMenuItem = new JMenuItem("Exit"); 
     exitMenuItem.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       SystemTray.getSystemTray().remove(trayIcon); 
       System.exit(0); 
      } 
     }); 

     popupMenu.add(exitMenuItem); 

     //Thanks to Artem Ananiev for this implementation idea 
     //https://weblogs.java.net/blog/ixmal/archive/2006/05/using_jpopupmen.html 
     trayIcon.addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseReleased(MouseEvent e) { 
       if(e.getButton() == MouseEvent.BUTTON3) { 
        popupMenu.setLocation(e.getX() - 40, e.getY() - 40); 
        popupMenu.setInvoker(popupMenu); 
        popupMenu.setVisible(true); 
       } 
      } 
     }); 

     popupMenu.addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseExited(MouseEvent e) { 
       popupMenu.setVisible(false); 
      } 
     }); 

     SystemTray.getSystemTray().add(trayIcon); 
    } 

} 
+0

Опубликовать Ваше 'SSCCE', демонстрирующую проблему. – camickr

+0

@camickr Сделано. Сделал это как можно более кратким, хотя это запутанная настройка. – asteri

ответ

3

Ничего себе, вы используете значок лотка sytem. Эта информация, возможно, была важна для понимания. Вот почему SSCCE должен быть опубликован с КАЖДОГО вопроса.

В любом случае следующий, кажется, работает:

if (! popupMenu.contains(e.getPoint())) 
    popupMenu.setVisible(false); 

Edit:

Похоже, что проблема заключается в том, что JSeparator не слушать MouseEvents по умолчанию, поэтому все события мыши передаются его родителей , Поэтому, когда вы покидаете JMenuItem, событие mouseEntered() генерируется для всплывающего меню, а затем, когда вы повторно вводите другой JMenuItem, генерируется событие mouseExited().

Если вы включите MouseEvents для JSeparator, то это выглядит как JPopupMenu не получить событие

//popupMenu.addSeparator(); 
popupMenu.add(new MySeparator()); 
... 


static class MySeparator extends JSeparator 
{ 
    public MySeparator() 
    { 
     super(JSeparator.HORIZONTAL); 
     enableEvents(AWTEvent.MOUSE_EVENT_MASK); 
    } 

    /** 
    * Returns the name of the L&F class that renders this component. 
    * 
    * @return the string "PopupMenuSeparatorUI" 
    * @see JComponent#getUIClassID 
    * @see UIDefaults#getUI 
    */ 
    public String getUIClassID() 
    { 
     return "PopupMenuSeparatorUI"; 

    } 
} 
+0

Да, отлично работает! Спасибо за обходной путь. Любая идея, с чего это происходит, однако? Кажется, это очень странное поведение. Не догадывался, что случилось. – asteri

+0

@JeffGohlke, думаю, я нашел answser. См. Править. – camickr

+0

Очень интересно. Спасибо за понимание. Хорошо знать. – asteri

Смежные вопросы