如何使用菜单

原文: https://docs.oracle.com/javase/tutorial/uiswing/components/menu.html

菜单提供了一种节省空间的方式,让用户可以选择其中一个选项。用户可以做出多种选择的其他组件包括组合框列出单选按钮微调器,和工具栏。如果您的任何菜单项执行的操作被另一个菜单项或工具栏按钮复制,则除了本节之外,您还应阅读如何使用操作

菜单的独特之处在于,按照惯例,菜单不会与 UI 中的其他组件放在一起。相反,菜单通常出现在菜单栏弹出菜单中。菜单栏包含一个或多个菜单,并具有通常的平台相关位置 - 通常位于窗口顶部。弹出菜单是一个不可见的菜单,直到用户在启用弹出窗口的组件上进行特定于平台的鼠标操作(例如按下鼠标右键)。然后弹出菜单出现在光标下。

下图显示了许多与菜单相关的组件:菜单栏,菜单,菜单项,单选按钮菜单项,复选框菜单项和分隔符。如您所见,菜单项可以包含图像或文本,或两者都有。您还可以指定其他属性,例如字体和颜色。

MenuLookDemo

本节的其余部分将向您介绍菜单组件,并告诉您如何使用各种菜单功能:

以下是与菜单相关的类的继承层次结构的图片:

The inheritance hierarchy for menu classes

如图所示,菜单项(包括菜单)只是按钮。您可能想知道菜单(如果它只是一个按钮)如何显示其菜单项。答案是,当菜单被激活时,它会自动弹出一个显示菜单项的弹出菜单。

以下代码创建此菜单部分开头附近显示的菜单。粗体代码行创建并连接菜单对象;其他代码设置或自定义菜单对象。您可以在 MenuLookDemo.java 中找到整个程序。其他所需文件列在示例索引中。


Try this:


因为此代码没有事件处理,所以菜单除了看起来应该没有任何用处。如果运行该示例,您会注意到尽管缺少自定义事件处理,菜单和子菜单应该出现,并且当用户选择它们时,复选框和单选按钮会做出相应的响应。

  1. //Where the GUI is created:
  2. JMenuBar menuBar;
  3. JMenu menu, submenu;
  4. JMenuItem menuItem;
  5. JRadioButtonMenuItem rbMenuItem;
  6. JCheckBoxMenuItem cbMenuItem;
  7. //Create the menu bar.
  8. menuBar = new JMenuBar();
  9. //Build the first menu.
  10. menu = new JMenu("A Menu");
  11. menu.setMnemonic(KeyEvent.VK_A);
  12. menu.getAccessibleContext().setAccessibleDescription(
  13. "The only menu in this program that has menu items");
  14. menuBar.add(menu);
  15. //a group of JMenuItems
  16. menuItem = new JMenuItem("A text-only menu item",
  17. KeyEvent.VK_T);
  18. menuItem.setAccelerator(KeyStroke.getKeyStroke(
  19. KeyEvent.VK_1, ActionEvent.ALT_MASK));
  20. menuItem.getAccessibleContext().setAccessibleDescription(
  21. "This doesn't really do anything");
  22. menu.add(menuItem);
  23. menuItem = new JMenuItem("Both text and icon",
  24. new ImageIcon("images/middle.gif"));
  25. menuItem.setMnemonic(KeyEvent.VK_B);
  26. menu.add(menuItem);
  27. menuItem = new JMenuItem(new ImageIcon("images/middle.gif"));
  28. menuItem.setMnemonic(KeyEvent.VK_D);
  29. menu.add(menuItem);
  30. //a group of radio button menu items
  31. menu.addSeparator();
  32. ButtonGroup group = new ButtonGroup();
  33. rbMenuItem = new JRadioButtonMenuItem("A radio button menu item");
  34. rbMenuItem.setSelected(true);
  35. rbMenuItem.setMnemonic(KeyEvent.VK_R);
  36. group.add(rbMenuItem);
  37. menu.add(rbMenuItem);
  38. rbMenuItem = new JRadioButtonMenuItem("Another one");
  39. rbMenuItem.setMnemonic(KeyEvent.VK_O);
  40. group.add(rbMenuItem);
  41. menu.add(rbMenuItem);
  42. //a group of check box menu items
  43. menu.addSeparator();
  44. cbMenuItem = new JCheckBoxMenuItem("A check box menu item");
  45. cbMenuItem.setMnemonic(KeyEvent.VK_C);
  46. menu.add(cbMenuItem);
  47. cbMenuItem = new JCheckBoxMenuItem("Another one");
  48. cbMenuItem.setMnemonic(KeyEvent.VK_H);
  49. menu.add(cbMenuItem);
  50. //a submenu
  51. menu.addSeparator();
  52. submenu = new JMenu("A submenu");
  53. submenu.setMnemonic(KeyEvent.VK_S);
  54. menuItem = new JMenuItem("An item in the submenu");
  55. menuItem.setAccelerator(KeyStroke.getKeyStroke(
  56. KeyEvent.VK_2, ActionEvent.ALT_MASK));
  57. submenu.add(menuItem);
  58. menuItem = new JMenuItem("Another item");
  59. submenu.add(menuItem);
  60. menu.add(submenu);
  61. //Build second menu in the menu bar.
  62. menu = new JMenu("Another Menu");
  63. menu.setMnemonic(KeyEvent.VK_N);
  64. menu.getAccessibleContext().setAccessibleDescription(
  65. "This menu does nothing");
  66. menuBar.add(menu);
  67. ...
  68. frame.setJMenuBar(_theJMenuBar_);

如代码所示,要设置JFrame的菜单栏,请使用setJMenuBar方法。要将JMenu添加到JMenuBar,请使用add(JMenu)方法。要将菜单项和子菜单添加到JMenu,请使用add(JMenuItem)方法。


Note:

菜单项与其他组件一样,最多可以包含一个容器。如果您尝试将菜单项添加到第二个菜单,则菜单项将从第一个菜单中删除,然后再添加到第二个菜单中。有关实现执行相同操作的多个组件的方法,请参阅如何使用操作


上述代码中的其他方法包括setAcceleratorsetMnemonic,稍后将在启用键盘操作中讨论。 setAccessibleDescription方法在如何支持辅助技术中讨论。

要检测用户何时选择JMenuItem,您可以监听动作事件(就像 JButton 一样)。要检测用户何时选择JRadioButtonMenuItem,您可以侦听动作事件或项目事件,如如何使用单选按钮中所述。对于JCheckBoxMenuItem,您通常会听取项目事件,如如何使用复选框中所述。


Try this:


The text area shows the action and item events our listeners detected.

以下是实现事件处理的代码:

  1. public class MenuDemo ... implements ActionListener,
  2. ItemListener {
  3. ...
  4. public MenuDemo() {
  5. //...for each JMenuItem instance:
  6. menuItem.addActionListener(this);
  7. ...
  8. //for each JRadioButtonMenuItem:
  9. rbMenuItem.addActionListener(this);
  10. ...
  11. //for each JCheckBoxMenuItem:
  12. cbMenuItem.addItemListener(this);
  13. ...
  14. }
  15. public void actionPerformed(ActionEvent e) {
  16. //...Get information from the action event...
  17. //...Display it in the text area...
  18. }
  19. public void itemStateChanged(ItemEvent e) {
  20. //...Get information from the item event...
  21. //...Display it in the text area...
  22. }

有关处理动作和项目事件的示例,请参阅按钮单选按钮复选框部分,以及示例列表在本节末尾。

菜单支持两种键盘选择:助记符和加速器。助记符提供了一种使用键盘导航菜单层次结构的方法,增加了程序的可访问性。另一方面,加速器提供键盘快捷键到旁路导航菜单层次结构。助记符适用于所有用户;加速器适用于高级用户。

助记符是使得已经可见的菜单项被选择的关键。例如,在MenuDemo中,第一个菜单具有助记符 A,而其第二个菜单项具有助记符 B.这意味着,当您使用 Java 外观运行MenuDemo时,按 Alt 和 A 键可使第一个菜单出现。当第一个菜单可见时,按 B 键(带或不带 Alt)可选择第二个菜单项。菜单项通常通过在菜单项的文本中下划线第一次出现的助记符来显示其助记符,如下面的快照所示。

B is the mnemonic character for this menu item

加速器是一种组合键,可以选择菜单项,无论它是否可见。例如,按MenuDemo中的 Alt 和 2 键可以选择第一个菜单子菜单中的第一个项目,而不会显示任何菜单。只有叶子菜单项 - 没有显示其他菜单的菜单 - 可以有加速器。以下快照显示 Java 外观如何显示具有加速器的菜单项。

Alt+2 advertises this menu item's accelerator

您可以在构造菜单项时或使用setMnemonic方法指定助记符。要指定加速器,请使用setAccelerator方法。以下是设置助记符和加速器的示例:

  1. //Setting the mnemonic when constructing a menu item:
  2. menuItem = new JMenuItem("A text-only menu item",
  3. KeyEvent.VK_T);
  4. //Setting the mnemonic after creation time:
  5. menuItem.setMnemonic(KeyEvent.VK_T);
  6. //Setting the accelerator:
  7. menuItem.setAccelerator(KeyStroke.getKeyStroke(
  8. KeyEvent.VK_T, ActionEvent.ALT_MASK));

如您所见,通过指定与用户应按下的键对应的 KeyEvent 常量来设置助记符。要指定加速器,必须使用 KeyStroke 对象,该对象组合了一个键(由KeyEvent常量指定)和一个修饰键掩码(由 ActionEvent [HTG5 指定] ] 不变)。


Note:

由于弹出菜单与常规菜单不同,并不总是由组件包含,因此弹出菜单项中的加速器不起作用,除非弹出菜单可见。


要调出弹出菜单( JPopupMenu ),您必须在弹出菜单应与之关联的每个组件上注册鼠标监听器。鼠标监听器必须检测弹出菜单的用户请求。

应该弹出弹出菜单的确切手势因外观而异。在 Microsoft Windows 中,按照惯例,用户通过释放鼠标右键来显示弹出菜单,同时光标位于启用弹出窗口的组件上。在 Java 外观中,惯常的触发器是按下鼠标右键(对于释放按钮时消失的弹出窗口)或单击它(对于弹出窗口保持不动)。


Try this:


  1. //...where instance variables are declared:
  2. JPopupMenu popup;
  3. //...where the GUI is constructed:
  4. //Create the popup menu.
  5. popup = new JPopupMenu();
  6. menuItem = new JMenuItem("A popup menu item");
  7. menuItem.addActionListener(this);
  8. popup.add(menuItem);
  9. menuItem = new JMenuItem("Another popup menu item");
  10. menuItem.addActionListener(this);
  11. popup.add(menuItem);
  12. //Add listener to components that can bring up popup menus.
  13. MouseListener popupListener = new PopupListener();
  14. output.addMouseListener(popupListener);
  15. menuBar.addMouseListener(popupListener);
  16. ...
  17. class PopupListener extends MouseAdapter {
  18. public void mousePressed(MouseEvent e) {
  19. maybeShowPopup(e);
  20. }
  21. public void mouseReleased(MouseEvent e) {
  22. maybeShowPopup(e);
  23. }
  24. private void maybeShowPopup(MouseEvent e) {
  25. if (e.isPopupTrigger()) {
  26. popup.show(e.getComponent(),
  27. e.getX(), e.getY());
  28. }
  29. }
  30. }

弹出菜单有一些有趣的实现细节。一个是每个菜单都有一个相关的弹出菜单。菜单激活后,它会使用其关联的弹出菜单显示其菜单项。

另一个细节是弹出菜单本身使用另一个组件来实现包含菜单项的窗口。根据弹出菜单显示的环境,弹出菜单可以使用轻量级组件(例如JPanel),“中等重量”组件(例如 Panel []来实现其“窗口”。 HTG1]),或重量级窗口(继承自 Window 的东西)。

轻量级弹出窗口比重量级窗口更有效,但在 Java SE Platform 6 Update 12 发布之前,如果 GUI 中有任何重量级组件,它们就无法正常工作。具体来说,当轻量级弹出窗口的显示区域与重量级组件的显示区域相交时,重量级组件被绘制在顶部。这是在 6u12 发布之前,我们建议不要混合重量级和轻量级组件的原因之一。如果您使用的是旧版本并且绝对需要在 GUI 中使用重量级组件,则可以调用JPopupMenu.setLightWeightPopupEnabled(false)来禁用轻量级弹出窗口。有关在 6u12 及更高版本中混合组件的信息,请参阅混合重量级和轻量级组件

由于菜单由普通的 Swing 组件组成,因此您可以轻松自定义它们。例如,您可以将任何轻量级组件添加到JMenuJMenuBar。并且因为JMenuBar使用 BoxLayout ,您可以通过向其添加不可见组件来自定义菜单栏的布局。以下是将 glue 组件添加到菜单栏的示例,以便最后一个菜单位于菜单栏的右边缘:

  1. //...create and add some menus...
  2. menuBar.add(Box.createHorizontalGlue());
  3. //...create the rightmost menu...
  4. menuBar.add(rightMenu);

Try this:


这是 MenuGlueDemo 显示的修改后的菜单布局:

MenuGlueDemo

更改菜单外观的另一种方法是更改​​用于控制菜单的布局管理器。例如,您可以将菜单栏的布局管理器从默认的从左到右BoxLayout更改为GridLayout等。


Try this:


这是MenuLayoutDemo创建的菜单布局图:

MenuLayoutDemo

下表列出了常用的菜单构造器和方法。使用菜单的 API 分为以下几类:

构造器或方法 目的
JMenuBar() 创建一个菜单栏。
JMenu add(JMenu) 将菜单添加到菜单栏的末尾。
void setJMenuBar(JMenuBar)

JMenuBar getJMenuBar() JAppletJDialogJFrameJInternalFrameJRootPane ]) | 设置或获取小程序对话框框架内部框架根窗格的菜单栏。 |

构造器或方法 目的
JMenu()

JMenu(String) JMenu(行动) | 创建一个菜单。该字符串指定要为菜单显示的文本。 Action指定菜单的文本和其他属性(参见如何使用操作)。 | | JMenuItem add(JMenuItem) JMenuItem add(String) | 将菜单项添加到菜单的当前末尾。如果参数是字符串,则菜单会自动创建一个显示指定文本的JMenuItem对象。 | | void addSeparator() | 将分隔符添加到菜单的当前末尾。 | | JMenuItem 插入(JMenuItem,int) void 插入(String,int) void insertSeparator(int) | 将菜单项或分隔符插入到指定位置的菜单中。第一个菜单项位于 0 位置,第二个菜单项位于位置 1,依此类推。 JMenuItemString参数的处理方式与相应的add方法相同。 | | void remove(JMenuItem) void remove(int) void removeAll() | 从菜单中删除指定的项目。如果参数是整数,则它指定要删除的菜单项的位置。 |

构造器或方法 目的
JPopupMenu()

JPopupMenu(String) | 创建一个弹出菜单。可选的字符串参数指定外观可能显示为弹出窗口一部分的标题。 | | JMenuItem add(JMenuItem) JMenuItem add(String) | 将菜单项添加到弹出菜单的当前末尾。如果参数是字符串,则菜单会自动创建一个显示指定文本的JMenuItem对象。 | | void addSeparator() | 将分隔符添加到弹出菜单的当前末尾。 | | void insert(Component,int) | 将菜单项插入指定位置的菜单中。第一个菜单项位于 0 位置,第二个菜单项位于位置 1,依此类推。 Component参数指定要添加的菜单项。 | | void remove(int) void removeAll() | 从菜单中删除指定的项目。如果参数是整数,则它指定要删除的菜单项的位置。 | | static void setLightWeightPopupEnabled(boolean) | 默认情况下,Swing 使用轻量级组件实现菜单窗口。如果您在 Swing 程序中使用任何重量级组件,这可能会导致问题,如打开弹出菜单中所述。 (这是避免使用重量级组件的几个原因之一。)作为解决方法,请调用JPopupMenu.setLightWeightPopupEnabled(false)。 | | void show(Component,int,int) | 在指定组件的坐标系中,在指定的 x,y 位置(按整数参数的顺序指定)显示弹出菜单。 |

构造器或方法 目的
JMenuItem()

JMenuItem(String) JMenuItem(Icon) JMenuItem(String,Icon) JMenuItem(String,int) JMenuItem(动作) | Creates an ordinary menu item. The icon argument, if present, specifies the icon that the menu item should display. Similarly, the string argument specifies the text that the menu item should display. The integer argument specifies the keyboard mnemonic to use. You can specify any of the relevant VK constants defined in the KeyEvent class. For example, to specify the A key, use KeyEvent.VK_A.带有Action参数的构造器设置菜单项的Action,从而使Action初始化菜单项的属性。有关详细信息,请参见如何使用操作。 | | JCheckBoxMenuItem() JCheckBoxMenuItem(String) JCheckBoxMenuItem(Icon) JCheckBoxMenuItem(String,Icon) JCheckBoxMenuItem(String,boolean) JCheckBoxMenuItem(String,Icon,boolean) | 创建一个菜单项,其外观和行为类似于复选框。字符串参数(如果有)指定菜单项应显示的文本。如果为布尔参数指定true,则最初选择(选中)菜单项。否则,最初取消选择菜单项。 | | JRadioButtonMenuItem() JRadioButtonMenuItem(String) JRadioButtonMenuItem(Icon) JRadioButtonMenuItem(String,Icon) JRadioButtonMenuItem(String,boolean) JRadioButtonMenuItem(Icon,boolean) JRadioButtonMenuItem(String,Icon,boolean) | 创建一个看起来像单选按钮的菜单项。字符串参数(如果有)指定菜单项应显示的文本。如果为布尔参数指定true,则最初选择菜单项。否则,最初取消选择菜单项。 | | void setState(boolean) boolean getState() (在JCheckBoxMenuItem中) | 设置或获取复选框菜单项的选择状态。 | | void setEnabled(boolean) | 如果参数为 true,则启用菜单项。否则,禁用菜单项。 | | void setMnemonic(int) | 设置启用键盘导航到菜单或菜单项的助记符。使用KeyEvent类中定义的 VK 常量之一。 | | void setAccelerator(KeyStroke) | 设置激活菜单项的加速器。 | | void setActionCommand(String) | 设置菜单项执行的操作的名称。 | | void addActionListener(ActionListener) void addItemListener(ItemListener) | 向菜单项添加事件监听器。有关详细信息,请参阅处理菜单项中的事件。 | | void setAction(Action) | 设置与菜单项关联的Action。有关详细信息,请参见如何使用操作。 | | | 许多前面的方法都是从AbstractButton继承的。有关AbstractButton提供的其他有用方法的信息,请参见 Button API 。 |

我们的一些例子中使用了菜单。

在哪里描述 笔记
MenuLookDemo 本节(创建菜单 一个简单的示例,它创建除弹出菜单之外的所有类型的菜单,但不处理菜单项中的事件。
MenuDemo 本节(处理菜单项中的事件 将事件处理添加到MenuLookDemo
PopupMenuDemo 本节(打开一个弹出菜单 将弹出菜单添加到MenuDemo
MenuGlueDemo 本节(自定义菜单布局 通过向菜单栏添加不可见组件来演示影响菜单布局。
MenuLayoutDemo 本节(自定义菜单布局 实现在垂直菜单栏中排列的侧面打开菜单。
MenuSelectionManagerDemo - 将高亮度检测添加到 MenuDemo。要查看此功能,请单击菜单,然后将鼠标移到任何菜单项或子菜单上。每秒一次,文本区域将更新有关当前突出显示的菜单项的信息,不要与用户最终选择的菜单项混淆。此演示使用默认 MenuSelectionManager ,它跟踪菜单层次结构的状态。
ActionDemo 如何使用行动 使用Action对象实现复制工具栏按钮提供的功能的菜单项。
Framework - 打开多个相同的框架,每个框架的菜单栏都有一个菜单。
InternalFrameDemo 如何使用内部框架 使用菜单项创建窗口。

请参阅使用 JavaFX UI 控件:菜单教程,了解如何在 JavaFX 中创建菜单。