2013-10-24 18 views
0

我有一個JPopupMenu其中包含一個內部JMenuaddSeparator()分隔符。由於一些奇怪的處理,我添加了一個MouseListenerJPopupMenu,這使得它在mouseExited事件中不可見。這工作正常,除了當鼠標試圖跨過分隔符時,它觸發事件(即使JPopupMenu是超級組件)。穿越內部分隔符時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

哇,您正在使用系統托盤圖標。這些信息可能很重要。這就是爲什麼每個問題都應該發佈SSCCE。

反正以下似乎工作:

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

編輯:

它看起來像問題是,這樣所有的鼠標事件傳遞給其父的JSeparator默認不聽MouseEvents 。因此,當您離開JMenuItem時,將爲彈出式菜單生成mouseEntered()事件,然後當您重新輸入另一個JMenuItem時,會生成mouseExited()事件。

如果您啓用的JSeparator MouseEvents那麼它看起來像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,我想我找到了答案。請參閱編輯。 – camickr

+0

非常有趣。感謝您的洞察力。很高興知道。 – asteri