如何在javafx中递归地添加菜单和子菜单?

klr1opcd  于 2021-07-09  发布在  Java
关注(0)|答案(2)|浏览(434)

我创造了 CustomMenuBar 扩展的类 javafx.scene.control.MenuBar ,我想实现的是只通过 String 如中所示的值 start 以下代码的方法:

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

字符串格式应该像菜单>子菜单>子菜单>等,这是一个例子,我只能添加一个子菜单菜单。我被困在这里,不知道该怎么做 addMenu 方法递归地添加所有菜单和子菜单。
最终结果如下:

编辑:
菜单和子菜单不应重复,它们应保持层次顺序。
编辑2:
custommenubar应该能够添加任意长度的嵌套子菜单。
例如
它应该与菜单>子菜单1>子菜单2>子菜单3一起工作
它应该与menu>submenu1>submenu2>submenu3>submenu4一起工作。
使用“功能表>子菜单1>子菜单2>子菜单3>子菜单4>…>…>等等。

sulc1iza

sulc1iza1#

您可以添加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());
            }
yzuktlbb

yzuktlbb2#

我尽量让它简单。我将把优化留给你。您可以在代码中找到注解,以获取有关整个流程和逻辑的更多信息。

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

正如操作所要求的那样,如果用户试图添加子菜单或菜单项,getmenu()现在将把以前的任何菜单项转换为菜单项。

相关问题