Java教程是为JDK 8编写的。本页描述的示例和实践不利用后续版本引入的改进,并可能使用不再可用的技术。
请参阅Java语言变化,了解Java SE 9及后续版本中更新的语言特性的摘要。
请参阅JDK发布说明,了解有关所有JDK版本的新功能、增强功能和已删除或弃用选项的信息。
菜单提供了一种节省空间的方式,让用户选择多个选项之一。用户可以使用其他组件进行一对多选择的包括组合框,列表,单选按钮,微调器和工具栏。如果您的任何菜单项执行的操作与另一个菜单项或工具栏按钮重复,则除了阅读本节外,您还应该阅读如何使用操作。
菜单独特之处在于,按照约定,它们不会与其他组件一起放置在UI中。相反,菜单通常出现在一个菜单栏或作为弹出菜单。菜单栏包含一个或多个菜单,并具有习惯的、平台相关的位置-通常在窗口的顶部。弹出菜单是一个在用户进行特定于平台的鼠标操作(例如按下右键)后才可见的菜单,该操作发生在启用弹出菜单的组件上。然后弹出菜单出现在光标下方。
下图显示了许多与菜单相关的组件:菜单栏、菜单、菜单项、单选按钮菜单项、复选框菜单项和分隔符。如您所见,菜单项可以有图像或文本,或者两者都有。您还可以指定其他属性,例如字体和颜色。
本节的其余部分将教您有关菜单组件的知识,并告诉您如何使用各种菜单功能:
下图显示了与菜单相关的类的继承层次结构:
如图所示,菜单项(包括菜单)只是一个按钮。您可能想知道,如果菜单只是一个按钮,它是如何显示其菜单项的。答案是,当菜单被激活时,它会自动弹出一个显示菜单项的弹出菜单。
下面的代码创建了在菜单部分开始处显示的菜单。粗体代码行创建并连接菜单对象;其他代码设置或自定义菜单对象。您可以在MenuLookDemo.java
中找到整个程序。其他所需文件在示例索引中列出。
因为这段代码没有事件处理,所以菜单除了显示应该有的外,没有其他有用的功能。如果您运行示例,您会注意到尽管缺少自定义事件处理,菜单和子菜单会在应该出现的时候出现,并且当用户选择复选框和单选按钮时,它们会做出适当的响应。
//创建GUI界面: JMenuBar 菜单栏; JMenu 菜单, 子菜单; JMenuItem 菜单项; JRadioButtonMenuItem 单选按钮菜单项; JCheckBoxMenuItem 复选框菜单项; //创建菜单栏。 菜单栏 = new JMenuBar(); //构建第一个菜单。 菜单 = new JMenu("菜单"); 菜单.setMnemonic(KeyEvent.VK_A); 菜单.getAccessibleContext().setAccessibleDescription( "此程序中唯一有菜单项的菜单"); 菜单栏.add(菜单); //一组菜单项 菜单项 = new JMenuItem("只有文本的菜单项", KeyEvent.VK_T); 菜单项.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_1, ActionEvent.ALT_MASK)); 菜单项.getAccessibleContext().setAccessibleDescription( "这个并不实际做任何事情"); 菜单.add(菜单项); 菜单项 = new JMenuItem("文本和图标", new ImageIcon("images/middle.gif")); 菜单项.setMnemonic(KeyEvent.VK_B); 菜单.add(菜单项); 菜单项 = new JMenuItem(new ImageIcon("images/middle.gif")); 菜单项.setMnemonic(KeyEvent.VK_D); 菜单.add(菜单项); //一组单选按钮菜单项 菜单.addSeparator(); ButtonGroup group = new ButtonGroup(); 单选按钮菜单项 = new JRadioButtonMenuItem("单选按钮菜单项"); 单选按钮菜单项.setSelected(true); 单选按钮菜单项.setMnemonic(KeyEvent.VK_R); group.add(单选按钮菜单项); 菜单.add(单选按钮菜单项); 单选按钮菜单项 = new JRadioButtonMenuItem("另一个"); 单选按钮菜单项.setMnemonic(KeyEvent.VK_O); group.add(单选按钮菜单项); 菜单.add(单选按钮菜单项); //一组复选框菜单项 菜单.addSeparator(); 复选框菜单项 = new JCheckBoxMenuItem("复选框菜单项"); 复选框菜单项.setMnemonic(KeyEvent.VK_C); 菜单.add(复选框菜单项); 复选框菜单项 = new JCheckBoxMenuItem("另一个"); 复选框菜单项.setMnemonic(KeyEvent.VK_H); 菜单.add(复选框菜单项); //一个子菜单 菜单.addSeparator(); 子菜单 = new JMenu("子菜单"); 子菜单.setMnemonic(KeyEvent.VK_S); 菜单项 = new JMenuItem("子菜单中的项"); 菜单项.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_2, ActionEvent.ALT_MASK)); 子菜单.add(菜单项); 菜单项 = new JMenuItem("另一个项"); 子菜单.add(菜单项); 菜单.add(子菜单); //在菜单栏中构建第二个菜单。 菜单 = new JMenu("另一个菜单"); 菜单.setMnemonic(KeyEvent.VK_N); 菜单.getAccessibleContext().setAccessibleDescription( "这个菜单什么也不做"); 菜单栏.add(菜单); ... frame.setJMenuBar(菜单栏);
代码示例中,要为 JFrame
设置菜单栏,使用 setJMenuBar
方法。要向 JMenuBar
添加 JMenu
,使用 add(JMenu)
方法。要向 JMenu
添加菜单项和子菜单,使用 add(JMenuItem)
方法。
菜单项,和其他组件一样,最多只能存在一个容器中。如果尝试将菜单项添加到第二个菜单中,在添加到第二个菜单之前,菜单项将从第一个菜单中移除。如果要实现多个组件执行相同操作的方式,请参阅 使用操作的方法。
在上述代码中,其他方法包括setAccelerator
和setMnemonic
,稍后在启用键盘操作中会讨论。 setAccessibleDescription
方法在如何支持辅助技术中进行了讨论。
要检测用户选择JMenuItem
的时候,您可以监听动作事件(就像对JButton
一样)。要检测用户选择JRadioButtonMenuItem
的时候,您可以监听动作事件或者项目事件,如如何使用单选按钮中所述。对于JCheckBoxMenuItem
,通常监听项目事件,如如何使用复选框中所述。
以下是实现事件处理的代码:
public class MenuDemo ... implements ActionListener, ItemListener { ... public MenuDemo() { //...对于每个JMenuItem实例: menuItem.addActionListener(this); ... //对于每个JRadioButtonMenuItem: rbMenuItem.addActionListener(this); ... //对于每个JCheckBoxMenuItem: cbMenuItem.addItemListener(this); ... } public void actionPerformed(ActionEvent e) { //...从动作事件获取信息... //...在文本区域中显示它... } public void itemStateChanged(ItemEvent e) { //...从项目事件获取信息... //...在文本区域中显示它... }
有关处理动作和项目事件的示例,请参见
菜单支持两种键盘操作方式:助记键和加速键。 助记键 提供了一种使用键盘导航菜单层次结构的方法,增加了程序的可访问性。另一方面,加速键 提供了绕过菜单层次结构的键盘快捷方式。助记键适用于所有用户;加速键适用于高级用户。
助记键是使已经可见的菜单项被选择的键。例如,在 MenuDemo
中,第一个菜单的助记键是 A,它的第二个菜单项的助记键是 B。这意味着当你使用 Java 的外观和感觉运行 MenuDemo
时,按下 Alt 和 A 键会使第一个菜单出现。当第一个菜单可见时,按下 B 键(带有或不带有 Alt)会选择第二个菜单项。菜单项通常通过在菜单项文本中对助记字符的第一次出现进行下划线显示助记键,如下图所示。
加速键是一种键组合,它使菜单项被选择,无论是否可见。例如,在 MenuDemo
中按下 Alt 和 2 键会选择第一个菜单的子菜单中的第一项,而不会弹出任何菜单。只有叶子菜单项(不弹出其他菜单的菜单)可以有加速键。下图显示了 Java 外观和感觉如何显示具有加速键的菜单项。
您可以在构建菜单项时指定助记键,也可以使用 setMnemonic
方法指定。要指定加速键,请使用 setAccelerator
方法。以下是设置助记键和加速键的示例:
// 在构建菜单项时设置助记键: menuItem = new JMenuItem("一个纯文本的菜单项", KeyEvent.VK_T); // 在创建后设置助记键: menuItem.setMnemonic(KeyEvent.VK_T); // 设置加速键: menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_T, ActionEvent.ALT_MASK));
如您所见,您可以通过指定与用户应按下的键对应的 KeyEvent
常量来设置助记键。要指定加速键,您必须使用一个 KeyStroke
对象,该对象将键(由 KeyEvent
常量指定)和修饰键掩码(由 ActionEvent
常量指定)组合在一起。
由于弹出菜单(与常规菜单不同)不总是由组件包含,因此弹出菜单项中的加速键只有在弹出菜单可见时才起作用。
要弹出弹出菜单(JPopupMenu
),必须在应该与弹出菜单关联的每个组件上注册一个鼠标监听器。鼠标监听器必须检测用户请求弹出菜单。
引起弹出菜单的确切手势因外观和感觉而异。在Microsoft Windows中,按照约定,当光标位于启用弹出菜单的组件上方时,用户通过释放右键来弹出弹出菜单。在Java外观和感觉中,通常的触发器是按下右键(对于在释放按钮时消失的弹出菜单)或点击它(对于保持打开的弹出菜单)。
//...在声明实例变量的位置: JPopupMenu popup; //...在构建GUI的位置: //创建弹出菜单。 popup = new JPopupMenu(); menuItem = new JMenuItem("一个弹出菜单项"); menuItem.addActionListener(this); popup.add(menuItem); menuItem = new JMenuItem("另一个弹出菜单项"); menuItem.addActionListener(this); popup.add(menuItem); //向可以弹出菜单的组件添加监听器。 MouseListener popupListener = new PopupListener(); output.addMouseListener(popupListener); menuBar.addMouseListener(popupListener); ... class PopupListener extends MouseAdapter { public void mousePressed(MouseEvent e) { maybeShowPopup(e); } public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { popup.show(e.getComponent(), e.getX(), e.getY()); } } }
弹出菜单有一些有趣的实现细节。其中一个是每个菜单都有一个关联的弹出菜单。当菜单被激活时,它使用其关联的弹出菜单来显示其菜单项。
另一个细节是弹出菜单本身使用另一个组件来实现包含菜单项的窗口。根据显示弹出菜单的情况,弹出菜单可以使用轻量级组件(如JPanel
),中等重量组件(如Panel
)或重型窗口(继承自Window
)来实现其“窗口”。
轻量级弹出窗口比重型窗口更高效,但在Java SE平台6 Update 12版本之前,如果GUI中有任何重型组件,它们在轻量级弹出窗口的显示区域与重型组件的显示区域相交时,重型组件会被绘制在顶部。这是在6u12版本之前我们推荐不要混合使用重型和轻量级组件的原因之一。如果您使用的是旧版本并且确实需要在GUI中使用重型组件,则可以调用JPopupMenu.setLightWeightPopupEnabled(false)
禁用轻量级弹出窗口。有关在6u12版本及更高版本中混合组件的信息,请参阅混合重型和轻量级组件。
因为菜单由普通的Swing组件组成,所以您可以轻松地自定义它们。例如,您可以向JMenu
或JMenuBar
添加任何轻量级组件。并且由于JMenuBar
使用了BoxLayout
,您可以通过向其中添加不可见组件来自定义菜单栏的布局。下面是一个向菜单栏添加占位符组件的示例,以便将最后一个菜单放在菜单栏的右边缘:
//...创建并添加一些菜单... menuBar.add(Box.createHorizontalGlue()); //...创建最右边的菜单... menuBar.add(rightMenu);
这是MenuGlueDemo显示的修改后的菜单布局:
改变菜单外观的另一种方法是改变用于控制它们的布局管理器。例如,您可以将菜单栏的布局管理器从默认的从左到右的BoxLayout
更改为GridLayout
等其他布局。
这是MenuLayoutDemo
创建的菜单布局的图片:
以下表格列出了常用的菜单构造函数和方法。使用菜单的 API 可以分为以下几类:
构造函数或方法 | 目的 |
---|---|
JMenuBar() | 创建一个菜单栏。 |
JMenu add(JMenu) | 将菜单添加到菜单栏的末尾。 |
void setJMenuBar(JMenuBar) JMenuBar getJMenuBar() (在 JApplet ,JDialog ,JFrame ,JInternalFrame ,JRootPane 中) |
设置或获取JApplet ,JDialog ,JFrame ,JInternalFrame 或JRootPane 的菜单栏。 |
构造函数或方法 | 目的 |
---|---|
JMenu() JMenu(String) JMenu(Action) |
创建一个菜单。字符串指定菜单显示的文本。Action指定菜单的文本和其他属性(请参阅如何使用Actions)。 |
JMenuItem add(JMenuItem) JMenuItem add(String) |
将菜单项添加到菜单的末尾。如果参数是字符串,则菜单会自动创建一个显示指定文本的JMenuItem对象。 |
void addSeparator() | 将分隔符添加到菜单的末尾。 |
JMenuItem insert(JMenuItem, int) void insert(String, int) void insertSeparator(int) |
在指定位置插入菜单项或分隔符。第一个菜单项位于位置0,第二个位于位置1,依此类推。JMenuItem和String参数在相应的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位置(按照整数参数的顺序指定)显示弹出菜单。 |
具有Action参数的构造函数设置菜单项的Action,从而使菜单项的属性从Action初始化。有关详细信息,请参阅如何使用Actions。
JCheckBoxMenuItem()JCheckBoxMenuItem
中)void setEnabled(boolean)void setMnemonic(int)KeyEvent
void setAccelerator(KeyStroke)void setActionCommand(String)void addActionListener(ActionListener)
Action
如何使用ActionsAbstractButton
AbstractButton
按钮API
我们的一些示例中使用了菜单。
示例 | 描述位置 | 备注 |
---|---|---|
MenuLookDemo |
本节 (创建菜单) | 一个简单的示例,创建了各种类型的菜单,但不处理菜单项的事件。 |
MenuDemo |
本节 (处理菜单项的事件) | 在MenuLookDemo 中添加了事件处理。 |
PopupMenuDemo |
本节 (弹出菜单) | 在MenuDemo 中添加了弹出菜单。 |
MenuGlueDemo |
本节 (自定义菜单布局) | 通过向菜单栏添加不可见组件来演示影响菜单布局。 |
MenuLayoutDemo |
本节 (自定义菜单布局) | 实现了以垂直菜单栏排列的侧向展开菜单。 |
MenuSelectionManagerDemo |
— | 在MenuDemo中添加了高亮检测功能。要查看此功能,请单击菜单,然后将鼠标移动到任何菜单项或子菜单上。每秒钟,文本区域将更新当前高亮菜单项的信息,不要与用户最终选择的菜单项混淆。此演示使用默认的MenuSelectionManager ,跟踪菜单层次的状态。 |
ActionDemo |
如何使用动作 | 使用Action 对象来实现通过工具栏按钮提供的功能的菜单项。 |
Framework |
— | 弹出多个具有菜单栏的相同框架。 |
InternalFrameDemo |
如何使用内部框架 | 使用菜单项创建窗口。 |
请查看JavaFX UI控件使用教程:菜单,学习如何在JavaFX中创建菜单。