【问题标题】:Dynamically building a menu动态构建菜单
【发布时间】:2013-08-05 11:18:32
【问题描述】:

目前我的程序有一个动态构建的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);

【问题讨论】:

    标签: java swing menu jtree


    【解决方案1】:

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

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

    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);
                }
            }
        }
    }
    

    【讨论】:

    • 这几乎是我在测试我的尝试之后现在所拥有的。谢谢。
    【解决方案2】:

    好的,我想出了这个。它没有经过详尽的测试,但似乎可以工作。

    获取菜单或菜单项名称的方法是通过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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-18
      • 1970-01-01
      • 2010-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多