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

2 に答える 2

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);
            }
        }
    }
}
于 2013-08-05T12:57:16.690 に答える
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);
于 2013-08-05T12:29:23.803 に答える