菜单是桌面应用程序选择选项的标准方法。
菜单和菜单项可以与选择选项快捷键组合,称为键盘快捷键。

创建菜单和菜单项

必须创建一个菜单栏javafx.scene.control.MenuBar对象来保存javafx.scene.control.Menu对象。
菜单对象可以包含Menu和javafx.scene.control.MenuItem对象。菜单可以包含其他菜单作为子菜单。MenuItems是Menu对象内的子选项。
以下代码显示如何创建菜单栏并添加菜单和菜单项。
Menu类是MenuItem的子类,它有一个getItems().add()方法,它能够添加诸如其他Menu和MenuItem实例的子元素。

  1. import javafx.application.Application;
  2. import javafx.application.Platform;
  3. import javafx.scene.Scene;
  4. import javafx.scene.control.CheckMenuItem;
  5. import javafx.scene.control.Menu;
  6. import javafx.scene.control.MenuBar;
  7. import javafx.scene.control.MenuItem;
  8. import javafx.scene.control.RadioMenuItem;
  9. import javafx.scene.control.SeparatorMenuItem;
  10. import javafx.scene.control.ToggleGroup;
  11. import javafx.scene.layout.BorderPane;
  12. import javafx.scene.paint.Color;
  13. import javafx.stage.Stage;
  14. public class Main extends Application {
  15. @Override
  16. public void start(Stage primaryStage) {
  17. BorderPane root = new BorderPane();
  18. Scene scene = new Scene(root, 300, 250, Color.WHITE);
  19. MenuBar menuBar = new MenuBar();
  20. menuBar.prefWidthProperty().bind(primaryStage.widthProperty());
  21. root.setTop(menuBar);
  22. // File menu - new, save, exit
  23. Menu fileMenu = new Menu("File");
  24. MenuItem newMenuItem = new MenuItem("New");
  25. MenuItem saveMenuItem = new MenuItem("Save");
  26. MenuItem exitMenuItem = new MenuItem("Exit");
  27. exitMenuItem.setOnAction(actionEvent -> Platform.exit());
  28. fileMenu.getItems().addAll(newMenuItem, saveMenuItem,
  29. new SeparatorMenuItem(), exitMenuItem);
  30. Menu webMenu = new Menu("Web");
  31. CheckMenuItem htmlMenuItem = new CheckMenuItem("HTML");
  32. htmlMenuItem.setSelected(true);
  33. webMenu.getItems().add(htmlMenuItem);
  34. CheckMenuItem cssMenuItem = new CheckMenuItem("CSS");
  35. cssMenuItem.setSelected(true);
  36. webMenu.getItems().add(cssMenuItem);
  37. Menu sqlMenu = new Menu("SQL");
  38. ToggleGroup tGroup = new ToggleGroup();
  39. RadioMenuItem mysqlItem = new RadioMenuItem("MySQL");
  40. mysqlItem.setToggleGroup(tGroup);
  41. RadioMenuItem oracleItem = new RadioMenuItem("Oracle");
  42. oracleItem.setToggleGroup(tGroup);
  43. oracleItem.setSelected(true);
  44. sqlMenu.getItems().addAll(mysqlItem, oracleItem,
  45. new SeparatorMenuItem());
  46. Menu tutorialManeu = new Menu("Tutorial");
  47. tutorialManeu.getItems().addAll(
  48. new CheckMenuItem("Java"),
  49. new CheckMenuItem("JavaFX"),
  50. new CheckMenuItem("Swing"));
  51. sqlMenu.getItems().add(tutorialManeu);
  52. menuBar.getMenus().addAll(fileMenu, webMenu, sqlMenu);
  53. primaryStage.setScene(scene);
  54. primaryStage.show();
  55. }
  56. public static void main(String[] args) {
  57. launch(args);
  58. }
  59. }

Video_2022-04-28_161022.wmv (221.8KB)

指定菜单项

要将选中的选项或单选按钮添加到菜单,可以使用MenuItem类作为菜单的子类。以下列表显示了可用作菜单选项的MenuItem子类。

  • javafx.scene.control.CheckMenuItem
  • javafx.scene.control.RadioMenuItem
  • javafx.scene.control.CustomMenuItem
  • javafx.scene.control.SeparatorMenuItem
  • javafx.scene.control.Menu

CheckMenuItem菜单项类似于复选框控件,允许用户选择项。
RadioMenuItem菜单项类似于RadioButton控件,允许用户从项目组中仅选择一个项目。
要创建自定义菜单项,可以使用CustomMenuItem类。SeparatorMenuItem是CustomMenuItem类型的派生类,并显示用于分隔菜单项的视线。使用CustomMenuItem将Slider添加到MenuItem上。可参考以下代码实现 -

  1. import javafx.application.Application;
  2. import javafx.scene.Group;
  3. import javafx.scene.Scene;
  4. import javafx.scene.control.CustomMenuItem;
  5. import javafx.scene.control.Menu;
  6. import javafx.scene.control.MenuBar;
  7. import javafx.scene.control.MenuItem;
  8. import javafx.scene.control.SeparatorMenuItem;
  9. import javafx.scene.control.Slider;
  10. import javafx.scene.paint.Color;
  11. import javafx.stage.Stage;
  12. public class Main extends Application {
  13. public static void main(String[] args) {
  14. Application.launch(args);
  15. }
  16. @Override
  17. public void start(Stage primaryStage) {
  18. primaryStage.setTitle("Menus");
  19. Group root = new Group();
  20. Scene scene = new Scene(root, 300, 250, Color.WHITE);
  21. MenuBar menuBar = new MenuBar();
  22. Menu menu = new Menu("File");
  23. menu.getItems().add(new MenuItem("New"));
  24. menu.getItems().add(new MenuItem("Save"));
  25. menu.getItems().add(new SeparatorMenuItem());
  26. menu.getItems().add(new MenuItem("Exit"));
  27. CustomMenuItem customMenuItem = new CustomMenuItem(new Slider());
  28. customMenuItem.setHideOnClick(false);
  29. menu.getItems().add(customMenuItem);
  30. menuBar.getMenus().add(menu);
  31. menuBar.prefWidthProperty().bind(primaryStage.widthProperty());
  32. root.getChildren().add(menuBar);
  33. primaryStage.setScene(scene);
  34. primaryStage.show();
  35. }
  36. }

image.png

菜单事件处理程序

要向菜单项添加事件处理程序,可以使用setOnAction()方法,它接收一个类型为EventHandler 的功能接口,它是在选择菜单项时调用的处理程序代码。

  1. import javafx.application.Application;
  2. import javafx.application.Platform;
  3. import javafx.scene.Scene;
  4. import javafx.scene.control.Menu;
  5. import javafx.scene.control.MenuBar;
  6. import javafx.scene.control.MenuItem;
  7. import javafx.scene.layout.BorderPane;
  8. import javafx.scene.paint.Color;
  9. import javafx.stage.Stage;
  10. public class Main extends Application {
  11. @Override
  12. public void start(Stage primaryStage) {
  13. BorderPane root = new BorderPane();
  14. Scene scene = new Scene(root, 300, 250, Color.WHITE);
  15. MenuBar menuBar = new MenuBar();
  16. menuBar.prefWidthProperty().bind(primaryStage.widthProperty());
  17. root.setTop(menuBar);
  18. Menu fileMenu = new Menu("File");
  19. MenuItem exitMenuItem = new MenuItem("Exit");
  20. fileMenu.getItems().add(exitMenuItem);
  21. exitMenuItem.setOnAction(actionEvent -> Platform.exit());
  22. menuBar.getMenus().addAll(fileMenu);
  23. primaryStage.setScene(scene);
  24. primaryStage.show();
  25. }
  26. public static void main(String[] args) {
  27. launch(args);
  28. }
  29. }

image.png

关键助记符

标准菜单通常具有键盘助记符(类似于快捷键),以在不使用鼠标的情况下选择菜单项。
用户可以按Alt键和带下划线_的字母来激活菜单,然后使用箭头键导航。要向菜单添加键助记符,使用String值调用构造函数,并在菜单或菜单项的文本中在所选字母前面放置一个下划线字符。
然后将true传递给setMnemonicParsing(true)方法。
以下代码创建一个使用字母“F”作为助记符的文件菜单。

  1. Menu fileMenu = new Menu("_File");
  2. fileMenu.setMnemonicParsing(true);

完整的源代码实现,如下所示 -

  1. import javafx.application.Application;
  2. import javafx.application.Platform;
  3. import javafx.scene.Scene;
  4. import javafx.scene.control.Menu;
  5. import javafx.scene.control.MenuBar;
  6. import javafx.scene.control.MenuItem;
  7. import javafx.scene.layout.BorderPane;
  8. import javafx.scene.paint.Color;
  9. import javafx.stage.Stage;
  10. public class Main extends Application {
  11. @Override
  12. public void start(Stage primaryStage) {
  13. BorderPane root = new BorderPane();
  14. Scene scene = new Scene(root, 300, 250, Color.WHITE);
  15. MenuBar menuBar = new MenuBar();
  16. menuBar.prefWidthProperty().bind(primaryStage.widthProperty());
  17. root.setTop(menuBar);
  18. Menu fileMenu = new Menu("_File");
  19. fileMenu.setMnemonicParsing(true);
  20. MenuItem exitMenuItem = new MenuItem("Exit");
  21. fileMenu.getItems().add(exitMenuItem);
  22. exitMenuItem.setOnAction(actionEvent -> Platform.exit());
  23. menuBar.getMenus().addAll(fileMenu);
  24. primaryStage.setScene(scene);
  25. primaryStage.show();
  26. }
  27. public static void main(String[] args) {
  28. launch(args);
  29. }
  30. }

键组合

键组合是用于选择菜单选项的键击的组合。键组合称为键盘快捷键。
例如,在Windows平台上,Ctrl + S的组合键可以保存文件。 在Mac OS平台上,组合键为Command + S.
Ctrl,Command,Alt,Shift和Meta等键称为修饰键。
通常,修饰符与单个字母组合使用。要创建一个组合键,使用KeyCodeCombination对象,并传入击键和修饰符。
以下代码创建(Ctrl或Meta)+ S的键代码组合。

  1. MenuItem saveItem = new MenuItem("_Save");
  2. saveItem.setMnemonicParsing(true);
  3. saveItem.setAccelerator(new KeyCodeCombination(KeyCode.S, KeyCombination.SHORTCUT_DOWN));

代码使用KeyCombination.SHORTCUT_DOWN值作为键修饰符,而不是CONTROL_DOWN或META_DOWN。SHORTCUT_DOWN值将使应用程序能够跨平台使用。
CONTROL_DOWN和META_DOWN值分别依赖于Windows和MacOS平台,但是SHORTCUT_DOWN在所有平台上都有效。

要响应鼠标右键单击,请添加一个事件处理程序,以监听右键单击事件并调用上下文菜单的show()方法。
以下代码设置了一个事件处理程序,以分别基于右键或左键单击来显示和隐藏上下文菜单。
hide()方法由主鼠标单击(左键单击)调用以删除上下文菜单。

  1. primaryStage.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent me) -> {
  2. if (me.getButton() == MouseButton.SECONDARY || me.isControlDown()) {
  3. contextFileMenu.show(root, me.getScreenX(), me.getScreenY());
  4. } else {
  5. contextFileMenu.hide();
  6. }
  7. });