我创建了扩展CustomMenuBar
的{{1}}类,我想要实现的是仅按javafx.scene.control.MenuBar
值添加新菜单,如String
方法所示以下代码:
start
字符串格式应该类似于 菜单> SubMenu> SubMenu>等 即可。
这是一个例子,我只能添加一个子菜单的菜单。我被困在这里,并且不知道让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;等等 。
答案 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());
}