2013-08-05 79 views
0

目前我的程序有一个动态构建的菜单JTree。我将菜单构建器传递给一个对象,该对象使用一个字符串数组描述它的路径,其中每个元素表示一个节点,然后将最终节点设置为调用该对象的方法。只有在节点不存在的情况下才会创建新节点,否则会检查子菜单并重复整个过程。动态构建菜单

我想切换到JMenu系统而不是树,但我有一些问题。

因此,例如,字符串数组看起来像:

["New", "Job", "Item A"] 
["New", "Job", "Item B"] 
["New", "Search", "Item C"] 

这一操作将创建一个树一样:

┬ New 
├──┬ Job 
│ ├── Item A 
│ └── Item B 
└──┬ Search 
    └── Item C 

现在我遇到的问题是我不能告诉如果子菜单已存在,其中JMenu。如何检查是否存在具有所需名称的子菜单?

下面是我如何建立JTree一个例子:

String[] nodeNames = pane.getNodeDirectory(); 
    MenuTreeNode targetNode = root; 
    int i = 0; 

    if(targetNode.getChildCount() > 0) { 
     //Search for the first node that doesn't exist in the pane's directory 
     for(; i < nodeNames.length; ++i) { 
      Enumeration e = targetNode.children(); 

      while(e.hasMoreElements()) { 
       MenuTreeNode node = (MenuTreeNode)e.nextElement(); 

       if(node.getName().equals(nodeNames[i])) { 
        targetNode = node; 
        break; 
       } 
      } 

      //We've been over all the children and none matched so we need 
      //to build the rest of the directory. 
      if(!e.hasMoreElements()) { 
       ++i; 
       break; 
      } 
     } 
    } 

    //Build the remainder of the pane's directory 
    for(; i < nodeNames.length; ++i) { 
     MenuTreeNode currentNode = new MenuTreeNode(nodeNames[i]); 

     targetNode.add(currentNode); 
     targetNode = currentNode; 
    } 

    targetNode.setContentPane(pane); 

    model.nodeStructureChanged(root); 

回答

0

您可以混合一些不同的方法调用和类型检查来完成此任务。

以下代码动态构建菜单,丢弃重复项。

public static void main(String[] args) { 
    // just example input 
    String[][] menuHierarchies = { 
      {"New", "Job", "Item A"}, 
      {"New", "Job", "Item B"}, 
      {"New", "Search", "Item C"}, 
      {"New", "Item D"}, 
      {"Other", "Item E"}, 
      {"New", "Job", "Item B"}, 
      {"Other", "Job", "Item B"} 
    }; 

    JMenuBar menuBar = new JMenuBar(); 

    // relevant code from here. It builds the menu removing redundancies 
    for (int rootIndex = 0; rootIndex < menuHierarchies.length; ++rootIndex) { 
     JMenu parentMenu = null; 

     for(int menuLevel = 0; menuLevel < menuHierarchies[rootIndex].length; ++menuLevel) { 
      // if it is root menu 
      if (menuLevel == 0) { 
       // checks if the root menu already exists 
       for (int i = 0; i < menuBar.getMenuCount(); ++i) { 
        if (menuBar.getMenu(i).getText().equals(menuHierarchies[rootIndex][menuLevel])) { 
         parentMenu = menuBar.getMenu(i); 
         break; 
        } 
       } 

       if (parentMenu == null) { 
        parentMenu = new JMenu(menuHierarchies[rootIndex][menuLevel]); 
        menuBar.add(parentMenu); 
       } 
      } else if (menuLevel < menuHierarchies[rootIndex].length - 1) { // if it is a non-leaf (and, of course, not a root menu) 
       Component[] menuComponents = parentMenu.getMenuComponents(); 
       JMenu currentMenu = null; 

       // checks if the menu already exists 
       for (Component component : menuComponents) { 
        if (component instanceof JMenu) { 
         if (((JMenu) component).getText().equals(menuHierarchies[rootIndex][menuLevel])) { 
          currentMenu = (JMenu) component; 
          break; 
         } 
        } 
       } 

       if (currentMenu == null) { 
        currentMenu = new JMenu(menuHierarchies[rootIndex][menuLevel]); 
        parentMenu.add(currentMenu); 
       } 

       parentMenu = currentMenu; 
      } else { // if it is a leaf 
       Component[] menuComponents = parentMenu.getMenuComponents(); 
       JMenuItem currentItem = null; 

       for (Component component : menuComponents) { 
        if (component instanceof JMenuItem) { 
         if (((JMenuItem) component).getText().equals(menuHierarchies[rootIndex][menuLevel])) { 
          currentItem = (JMenuItem) component; 
          break; 
         } 
        } 
       } 

       if (currentItem == null) { 
        parentMenu.add(new JMenuItem(menuHierarchies[rootIndex][menuLevel])); 
       } 
      } 
     } 
    } 
} 

以下方法打印内置菜单的层次结构,用于测试目的:

private static void printMenu(JMenuBar menuBar) { 
    for (int i = 0; i < menuBar.getMenuCount(); ++i) { 
     printMenu(menuBar.getMenu(i), 0); 
    } 
} 

private static void printMenu(JMenuItem menuItem, int level) { 
    for (int i = 0; i < level; ++i) { 
     System.out.print("\t"); 
    } 

    System.out.println("\\" + menuItem.getText()); 

    if (menuItem instanceof JMenu) { 
     JMenu menu = (JMenu) menuItem; 

     Component[] menuComponents = menu.getMenuComponents(); 

     for (Component component : menuComponents) { 
      if (component instanceof JMenuItem) { 
       printMenu((JMenuItem) component, level+1); 
      } 
     } 
    } 
} 
+0

这差不多就是我现在测试我尝试多一些之后有。谢谢。 – Lerp

0

好吧,我想出了这一点。它没有经过彻底的测试,但它似乎工作。

获取菜单或菜单项名称的方法是通过Accessible界面。我假定所有分支都是JMenu。我不确定这个假设有多安全。

String[] nodeNames = pane.getNodeDirectory(); 
    JMenu currentMenu = null; 
    int i = 0; 

    for(int m = 0; m < menuBar.getMenuCount(); ++m) { 
     String name = menuBar.getMenu(m).getAccessibleContext().getAccessibleName(); 

     if(name.equals(nodeNames[i])) { 
      currentMenu = menuBar.getMenu(m); 
      break; 
     } 
    } 

    ++i; 

    if(currentMenu != null && currentMenu.getMenuComponentCount() > 0) { 
     boolean startBuild = false; 

     //Find the first non existant child 
     for(; i < nodeNames.length; ++i) { 
      for(int j = 0; j < currentMenu.getMenuComponentCount(); ++j) { 

       Component c = currentMenu.getMenuComponent(j); 

       //If we're not at the leaf node search for a JMenu and if it 
       //has the correct name set it as the current menu and move 
       //onto the next node. 
       if(i < nodeNames.length - 1 && c instanceof JMenu) { 
        String name = ((Accessible)c).getAccessibleContext().getAccessibleName(); 

        if(name.equals(nodeNames[i])) { 
         currentMenu = (JMenu)c; 
         break; 
        } 
       //If we're at the leaf node search for a JMenuItem to make 
       //sure the requested item doesn't already exist 
       } else if(i == nodeNames.length - 1 && c instanceof JMenuItem) { 
        String name = ((Accessible)c).getAccessibleContext().getAccessibleName(); 

        if(name.equals(nodeNames[i])) { 
         return; 
        } 
       } 

       //If we've reached the last component without finding an 
       //appropriate item start building the menu 
       if(j == currentMenu.getMenuComponentCount() - 1) { 
        startBuild = true; 
       } 
      } 

      if(startBuild) { 
       break; 
      } 
     } 
    } else if(currentMenu == null) { 
     currentMenu = new JMenu(nodeNames[i]); 
     menuBar.add(currentMenu); 
    } 

    //Continue the loop from where we left off but this time making the 
    //missing nodes instead of searching for existing nodes. 
    for(; i < nodeNames.length - 1; ++i) { 
     JMenu newMenu = new JMenu(nodeNames[i]); 

     currentMenu.add(newMenu); 
     currentMenu = newMenu; 
    } 

    JMenuItem item = new JMenuItem(nodeNames[nodeNames.length - 1]); 
    item.addActionListener(new ActionListener() { 
     @Override public void actionPerformed(ActionEvent e) { 
      pane.giveFocus(); 
     } 
    }); 

    currentMenu.add(item);