2016-11-14 100 views
0

我知道如何使用JMenu創建Java Swing子菜單。當我們將鼠標懸停在一個JMenu的對象,它會顯示一個JPopupMenu中顯示的子菜單項,如:使用JMenu的動態創建Java Swing子菜單

https://i.stack.imgur.com/K6yz8.png

子菜單我的問題是,在我的應用程序,確定哪些菜單元素將有一個子菜單是昂貴的。我不想事先確定一個特定的菜單元素是JMenu還是JMenuItem。我想讓每個元素都成爲JMenuItem,並且只有當用戶請求時才顯示子菜單,例如,將鼠標懸停在菜單項上。像這樣:

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class Menu2 extends JFrame 
{ 
    public Menu2() 
    { 
    super("Menu2"); 
    JMenuBar menuBar = new JMenuBar(); 
    setJMenuBar(menuBar); 
    JMenu mItems = new JMenu("Items"); 
    menuBar.add(mItems); 
    mItems.add(new JMI("A")); 
    mItems.add(new JMI("B")); 
    mItems.add(new JMI("C")); 
    JLabel stuff = new JLabel("Other stuff"); 
    stuff.setPreferredSize(new Dimension(200,200)); 
    getContentPane().add(stuff); 
    pack(); 
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    setLocationRelativeTo(null); 
    } 

    private class JMI extends JMenuItem 
    implements MouseListener 
    { 
    public JPopupMenu childrenPopup = null; 

    public JMI(String label) 
    { 
     super(label); 
     addMouseListener(this); 
    } 

    // MouseListener 

    public void mouseClicked(MouseEvent ev) {} 
    public void mouseEntered(MouseEvent ev) 
    { 
     // Show a submenu for item "B" only. 
     // In real life we'd want a Timer to delay showing the submenu 
     // until we are sure the user is hovering the mouse. 
     // For simplicity I've omitted it. 

     if (getText().equals("B")) { 
     if (childrenPopup == null) { 
      childrenPopup = new JPopupMenu(); 
      // Expensive processing to determine submenu elements... 
      childrenPopup.add("D"); 
      childrenPopup.add("E"); 
     } 
     // Display the submenu 
     childrenPopup.show(this,getWidth(),0); 
     } 
    } 
    public void mouseExited(MouseEvent ev) {} 
    public void mousePressed(MouseEvent ev) {} 
    public void mouseReleased(MouseEvent ev) {} 
    } 


    public static void main(String[] args) 
    throws Exception 
    { 
    new Menu2().setVisible(true); 
    } 
} 

唯一的問題是當我手動創建的JPopupMenu被顯示時,菜單的其餘部分被關閉。顯示結果並不像較早的企業之一,而像這樣:

子菜單手動顯示

https://i.stack.imgur.com/cqV7q.png

請注意,我沒有點擊在「B」菜單項,只有感動將鼠標放入它。由於鼠標點擊,菜單沒有關閉。

我該如何做JMenu所做的 - 在不關閉菜單的其餘部分的情況下顯示JPopupMenu?

+0

也許你可以嘗試用JMenu的替代JMenuItem的,一旦你確定它確實確實有子菜單。 – camickr

+0

我認爲像這樣的一個新成語會讓用戶感到困惑,並且最好讓菜單條目始終是一個JMenuItem,它會顯示一個顯示動態確定選項的模式對話框(可能是一個JOptionPane)。 – VGR

+0

謝謝,camickr和VGR,爲您提供瞭解決方法的建議。即使我必須使用解決方法,我也確實想知道爲什麼顯示彈出菜單會導致菜單關閉。很明顯,它可以在不關閉菜單的情況下完成,因爲JMenu可以做到這一點。 – Vine

回答

0

我暫時決定的方法是擴展JMenu,而不是JMenuItem的 ,並使用這種類型的全部我的菜單元素。但我 將不會填充這些元素(昂貴的步驟),直到用戶 通過懸停鼠標請求它。

爲了避免使用JMenu 通常顯示的箭頭圖標(在這種情況下可能會產生誤導)混淆菜單,我使用a technique described by Stackoverflow's MadProgrammer在靜態工廠方法中實例化無箭頭的JMenu。由於我在創建無箭頭JMenu後恢復箭頭圖標屬性,因此在其他位置創建的普通JMenu實例仍將顯示箭頭。

某些菜單元素將需要執行操作並關閉菜單,如JMenuItem所做的那樣,菜單 。 JMenu通常不響應鼠標 點擊,所以我在我的MouseListener中執行點擊操作。

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.event.*; 

public class Menu3 extends JFrame 
{ 
    public Menu3() 
    { 
    super("Menu3"); 
    JMenuBar menuBar = new JMenuBar(); 
    setJMenuBar(menuBar); 
    JMenu mItems = new JMenu("Items"); 
    menuBar.add(mItems); 
    mItems.add(JM.create("A")); 
    mItems.add(JM.create("B")); 
    mItems.add(JM.create("C")); 
    JLabel stuff = new JLabel("Other stuff"); 
    stuff.setPreferredSize(new Dimension(200,200)); 
    getContentPane().add(stuff); 
    pack(); 
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    setLocationRelativeTo(null); 
    } 

    private static class JM extends JMenu 
    implements MouseListener 
    { 
    private static final String ARROW_ICON_KEY = "Menu.arrowIcon"; 

    private boolean populated = false; // Submenu already populated? 

    protected JM(String label) 
    { 
     super(label); 
     addMouseListener(this); 
    } 

    // This static factory method returns a JM without an arrow icon. 

    public static JM create(String label) 
    { 
     UIDefaults uiDefaults = UIManager.getLookAndFeelDefaults(); 
     Object savedArrowIcon = uiDefaults.get(ARROW_ICON_KEY); 
     uiDefaults.put(ARROW_ICON_KEY,null); 
     JM newJM = new JM(label); 
     uiDefaults.put(ARROW_ICON_KEY,savedArrowIcon); 
     return newJM; 
    } 

    // MouseListener 

    public void mouseClicked(MouseEvent ev) 
    { 
     // Since some menu elements need to execute actions and a JMenu 
     // doesn't normally respond to mouse clicks, we execute click 
     // actions here. In real life we'll probably fire some event 
     // for which an EventListener can listen. For illustrative 
     // purposes we'll just write out a trace message. 

     System.err.println("Executing "+getText()); 
     MenuSelectionManager.defaultManager().clearSelectedPath(); 
    } 
    public void mouseEntered(MouseEvent ev) 
    { 
     // In real life we'd want a Timer to delay showing the submenu 
     // until we are sure the user is "hovering" the mouse. 
     // For simplicity I've omitted it. 

     // Populate this submenu only once 
     if (!populated) { 
     // For purposes of example, show a submenu for item "B" only. 
     if (getText().equals("B")) { 
      // Expensive processing... 
      add(create("D")); 
      add(create("E")); 
     } 
     populated = true; 
     } 
    } 
    public void mouseExited(MouseEvent ev) {} 
    public void mousePressed(MouseEvent ev) {} 
    public void mouseReleased(MouseEvent ev) {} 
    } 

    public static void main(String[] args) 
    throws Exception 
    { 
    new Menu3().setVisible(true); 
    } 
} 

結果工作的方式我想:

Menu3 with open menu