2012-01-18 196 views
3

注:您可能需要编译和运行我的例子完全明白我的问题。如果这不是犹太教,我提前道歉。Java的弹出式菜单按钮

我想创建一个基于JToggleButtonJPopupMenu的Swing控件。

的切换按钮被选中当且仅当在弹出菜单中是可见的,并且拨动按钮被取消当且仅当在弹出菜单中是不可见的。因此,该行为类似于JComboBox,但弹出窗口可以包含任意组件。

下面的代码是我将如何创建控件的一个例子(除了它将在它自己的类中...像JPopupToggleButton之类的东西)。不幸的是,它根据不同的外观和感觉呈现出不同的行为(我已经用Metal和Nimbus进行了测试)。

这里发布的代码在Metal中的行为与预期相同,但不在Nimbus中。使用Nimbus时,只需反复点击切换按钮即可显示并隐藏弹出窗口,您将看到我的意思。

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.MouseInfo; 
import java.awt.Point; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.*; 
import javax.swing.event.PopupMenuEvent; 
import javax.swing.event.PopupMenuListener; 

public class PopupButtonExample extends JFrame 
{ 
    public static void main(String[] args) 
    { 
     java.awt.EventQueue.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       PopupButtonExample example = new PopupButtonExample(); 
       example.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       example.setVisible(true); 
      } 
     }); 
    } 

    public PopupButtonExample() 
    { 
     super("Components in Popup"); 

     JPanel popupPanel = new JPanel(); 
     popupPanel.setLayout(new BorderLayout()); 
     popupPanel.add(new JLabel("This popup has components"), 
       BorderLayout.NORTH); 
     popupPanel.add(new JTextArea("Some text", 15, 20), 
       BorderLayout.CENTER); 
     popupPanel.add(new JSlider(), BorderLayout.SOUTH); 

     final JPopupMenu popupMenu = new JPopupMenu(); 
     popupMenu.add(popupPanel); 

     final JToggleButton popupButton = new JToggleButton("Show Popup"); 
     popupButton.addActionListener(new ActionListener() 
     { 
      @Override 
      public void actionPerformed(ActionEvent e) 
      { 
       if(popupButton.isSelected()) 
        popupMenu.show(popupButton, 0, popupButton.getHeight()); 
      } 
     }); 

     popupMenu.addPopupMenuListener(new PopupMenuListener() 
     { 
      @Override 
      public void popupMenuWillBecomeVisible(PopupMenuEvent pme) {} 

      @Override 
      public void popupMenuCanceled(PopupMenuEvent pme) {} 

      @Override 
      public void popupMenuWillBecomeInvisible(PopupMenuEvent pme) { 
       Point mouseLoc = MouseInfo.getPointerInfo().getLocation(); 
       Point componentLoc = popupButton.getLocationOnScreen(); 
       mouseLoc.x -= componentLoc.x; 
       mouseLoc.y -= componentLoc.y; 
       if(!popupButton.contains(mouseLoc)) 
        popupButton.setSelected(false); 
      } 
     }); 

     JPanel toolBarPanel = new JPanel(); 
     toolBarPanel.add(popupButton); 
     JToolBar toolBar = new JToolBar(); 
     toolBar.add(toolBarPanel); 

     setLayout(new BorderLayout()); 
     add(toolBar, BorderLayout.PAGE_START); 
     setPreferredSize(new Dimension(640, 480)); 
     pack(); 
    } 
} 

Commeting出以下行使得像预期的那样在雨云的代码,而不是在金属。再次,只要继续点击切换按钮来查看我的意思。

//    Point mouseLoc = MouseInfo.getPointerInfo().getLocation(); 
//    Point componentLoc = popupButton.getLocationOnScreen(); 
//    mouseLoc.x -= componentLoc.x; 
//    mouseLoc.y -= componentLoc.y; 
//    if(!popupButton.contains(mouseLoc)) 

因此,这里有我的两个问题:

(1)在雨云,为什么隐藏弹出面板不会被传递到切换按钮,因为它与金属做的点击?

(2)我怎样才能解决这个问题,以便它与所有的作品的外观和感觉?

+2

+1张贴http://sscce.org/,漂亮的问题 – mKorbel 2012-01-18 21:46:55

回答

0

经过一番调查后,我发现导致Nimbus和金属之间的区别。以下标志用于(至少由BasicPopupMenuUI)来控制事件的消耗当弹出关闭:

UIManager.getBoolean("PopupMenu.consumeEventOnClose"); 

当使用雨云,这将返回true。使用金属时,返回false。因此,popupMenuWillBecomeInvisible应该被定义为方法如下:

if(UIManager.getBoolean("PopupMenu.consumeEventOnClose")) 
{ 
    popupButton.setSelected(false); 
} 
else 
{ 
    Point mouseLoc = MouseInfo.getPointerInfo().getLocation(); 
    Point componentLoc = popupButton.getLocationOnScreen(); 
    mouseLoc.x -= componentLoc.x; 
    mouseLoc.y -= componentLoc.y; 
    if(!popupButton.contains(mouseLoc)) 
    { 
     popupButton.setSelected(false); 
    } 
} 
4
  • 雨云是漏洞太多(和发展的地方结束了在中间),我看你需要三个鼠标点击对JToggleButton与金属

  • 每一个标准的L &˚F比较已经得到自己的具体问题,尤其是SystemLookAndFeel

  • 使用的JWindow宁可JPopup,因为JPopup有另一个错误也如JPopup与JCombobox

+1

+1对JWindow。然后,您还可以使用'WindowListener'并处理'windowDeactivated()'事件来隐藏窗口并重置切换按钮。 – camickr 2012-01-18 22:33:06

+0

感谢您的回复。看起来怪异的是Oracle把Nimbus移到了javax.swing中。如果他们只开发了一半,然后停止,则使用JDK 7的plaf软件包。至于使用JWindow而不是Popup,我很好奇人们用Popup/JPopupMenu所遇到的问题。总是似乎对我很好,但我没有和Swing一起工作太久。 – lifelongcoug 2012-01-19 05:58:09