如何在JavaFX中递归添加Menus和SubMenus?

时间:2017-10-31 12:24:07

标签: java recursion javafx

我创建了扩展CustomMenuBar的{​​{1}}类,我想要实现的是仅按javafx.scene.control.MenuBar值添加新菜单,如String方法所示以下代码:

start

字符串格式应该类似于 菜单&gt; SubMenu&gt; SubMenu&gt;等 即可。 这是一个例子,我只能添加一个子菜单的菜单。我被困在这里,并且不知道让package recursivemenu; import javafx.application.Application; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; import javafx.scene.control.MenuItem; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public class RecursivelyAddMenuAndSubMenu extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { String menu1 = "File > Open"; String menu2 = "File > Close"; String menu3 = "File > Recently closed > File1"; String menu4 = "File > Recently closed > File2"; String menu5 = "File > Recently closed > File3"; String menu6 = "File > Recently closed > File4"; String menu7 = "File > Recently closed > File5"; CustomMenuBar customMenuBar = new CustomMenuBar(); customMenuBar.addMenu(menu1); customMenuBar.addMenu(menu2); customMenuBar.addMenu(menu3); customMenuBar.addMenu(menu4); customMenuBar.addMenu(menu5); customMenuBar.addMenu(menu6); customMenuBar.addMenu(menu7); BorderPane borderPane = new BorderPane(); borderPane.setTop(customMenuBar); Scene scene = new Scene(borderPane); primaryStage.setScene(scene); primaryStage.setMaximized(true); primaryStage.show(); } class CustomMenuBar extends MenuBar { void addMenu(String menu) { String[] menuChain = splitMenus(menu); // Add new top menu if not exists. if (getMenu(menuChain[0], getMenus()) == null) createMenu(menuChain[0]); // Adding sub menus Menu topMenu = getMenu(menuChain[0], getMenus()); if (topMenu.getItems().isEmpty()) { addSubMenu(topMenu, menuChain[1]); } else { // Add sub menu if not exists. if (getItem(menuChain[1], topMenu.getItems()) == null) createSubMenu(menuChain[1], topMenu); } } private void createSubMenu(String subMenuText, Menu menu) { menu.getItems().add(new MenuItem(subMenuText)); } private MenuItem getItem(String subMenuText, ObservableList<MenuItem> items) { for (MenuItem item : items) { if (item.getText().equals(subMenuText)) { return item; } } return null; } private void addSubMenu(Menu topMenu, String subMenuText) { topMenu.getItems().add(new MenuItem(subMenuText)); } private void createMenu(String menuText) { getMenus().add(new Menu(menuText)); } private Menu getMenu(String menuText, ObservableList<Menu> menus) { for (Menu menu : menus) { if (menu.getText().equals(menuText)) return menu; } return null; } private String[] splitMenus(String menuText) { String[] menuChain = menuText.split("\\s*>\\s*"); for (int i = 0; i < menuChain.length; i++) menuChain[i] = menuChain[i].trim(); return menuChain; } } } 方法递归地添加所有菜单和子菜单。

最终结果应如下所示:

修改
菜单和子菜单不应重复,它们必须保持层次结构序列。

EDIT2:
CustomMenuBar应该能够添加任何长度的嵌套子菜单。

e.g。
它应该与 菜单&gt;一起使用SubMenu1&gt; SubMenu2&gt; SubMenu3
它应该与 菜单&gt;一起使用SubMenu1&gt; SubMenu2&gt; SubMenu3&gt; SubMenu4 太。
并使用 菜单&gt; SubMenu1&gt; SubMenu2&gt; SubMenu3&gt; SubMenu4&gt; ...&gt; ...&GT;等等

2 个答案:

答案 0 :(得分:6)

我尽量保持简单。我会把优化留给你。您可以在代码中找到有关整个过程和逻辑的更多信息的注释。

import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class RecursivelyAddMenuAndSubMenu extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        String menu1 = "File > Open";
        String menu2 = "File > Close";
        String menu3 = "File > Recently closed > File1";
        String menu4 = "File > Recently closed > File2";
        String menu5 = "File > Recently closed > File3";
        String menu6 = "File > Recently closed > File4";
        String menu7 = "File > Recently closed > File5";
        String menu8 = "File > Recently closed > File5 > something";

        CustomMenuBar customMenuBar = new CustomMenuBar();
        customMenuBar.addMenu(menu1);
        customMenuBar.addMenu(menu2);
        customMenuBar.addMenu(menu3);
        customMenuBar.addMenu(menu4);
        customMenuBar.addMenu(menu5);
        customMenuBar.addMenu(menu6);
        customMenuBar.addMenu(menu7);
        customMenuBar.addMenu(menu8);

        BorderPane borderPane = new BorderPane();
        borderPane.setTop(customMenuBar);
        Scene scene = new Scene(borderPane);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    class CustomMenuBar extends MenuBar {

        private Menu currentMenu;
        private Menu head;

        void addMenu(String menu) {
            String tokens[] = splitMenusInHalf(menu);

            // we found something like "x -> y ... "
            if (tokens.length > 1) {

                // search for the current root if it contains
                // the menu we are about to create
                currentMenu = this.getMenu(tokens[0], head);
                boolean isAdded = true;

                // if not create it
                if (currentMenu == null) {
                    currentMenu = new Menu(tokens[0]);
                    isAdded = false;
                }

                // find out if there was a previous Menu created
                // if so the current is a sub-menu of the previous one
                if (head == null) {
                    head = currentMenu;
                    if (!isAdded) {
                        this.getMenus().add(currentMenu);
                    }
                } else {
                    if (!isAdded) {
                        // otherwise add the current Menu as sub-menu
                        head.getItems().add(currentMenu);
                    }
                    // set the Current "head" the sub-menu
                    head = currentMenu;
                }
                // Recursive check for more menus or menuItems
                addMenu(tokens[1]);
            } else {
                // If found only something like "x" which is MenuItem
                currentMenu.getItems().add(new MenuItem(tokens[0]));
                // reset everything for the next addMenu call
                currentMenu = null;
                head = null;
            }
        }

        private Menu getMenu(String menuText, Menu root) {
            if (root == null) {
                ObservableList<Menu> allMenus = this.getMenus();
                for (Menu m : allMenus) {
                    if (m.getText().equals(menuText)) {
                        return m;
                    }
                }
            } else {
                ObservableList<MenuItem> allMenus = root.getItems();
                for (MenuItem m : allMenus) {
                    if (m.getText().equals(menuText)) {
                        // We are about to convert MenuItem to Menu
                        if (!(m instanceof Menu)) {

                            // Get the previous menuItem location
                            int index = allMenus.indexOf(m);
                            // Remove it
                            allMenus.remove(m);
                            // Create a new Menu with the previous MenuItem text
                            m = new Menu(menuText);
                            // Add it to the correct location
                            allMenus.add(index, m);
                        }
                        return (Menu) m;
                    }
                }
            }
            return null;
        }

        private String[] splitMenusInHalf(String menuText) {
            String[] menuChain = menuText.split("\\s*>\\s*", 2);
            for (int i = 0; i < menuChain.length; i++)
                menuChain[i] = menuChain[i].trim();
            return menuChain;
        }
    }
}

当OP询问getMenu()时,如果用户试图在其上添加子菜单或MenuItem,则现在将任何以前的MenuItem转换为Menu。

答案 1 :(得分:0)

您可以添加for循环,将每次迭代时创建的菜单设置为顶层菜单:

            for (int i = 1; i < menuChain.length; i++) {
                if (topMenu.getItems().isEmpty()) {
                    addSubMenu(topMenu, menuChain[i]);
                } else {
                    // Add sub menu if not exists.
                    if (getItem(menuChain[i], topMenu.getItems()) == null)
                        createSubMenu(menuChain[i], topMenu);
                }  
                topMenu = getItem(menuChain[i], topMenu.getItems());
            }