11.6 AWT菜单

11.6 AWT菜单

前面介绍了创建GUI界面的方式:将AWT组件按某种布局摆放在容器内即可。创建AWT菜单的方式与此完全类似:将菜单条、菜单、菜单项组合在一起即可。

11.6.1 菜单条、菜单和菜单项

AWT中的菜单由如下几个类组合而成。

描述
MenuBar 菜单条,菜单的容器。
Menu 菜单组件,菜单项的容器。它也是MenuItem的子类,所以可作为菜单项使用。
PopupMenu 上下文菜单组件(右键菜单组件)。
MenuItem 菜单项组件。
CheckboxMenuItem 复选框菜单项组件。
MenuShortcut 菜单快捷键组件

图11.24显示了AWT菜单组件类之间的继承、组合关系。

这里有一张图片

从图中可以看出,MenuBarMenu都实现了菜单容器接口,所以MenuBar可用于盛装Menu,而Menu可用于盛装MenuItem(包括Menu和CheckboxMenuItem两个子类对象)。

Menu还有一个子类PopupMenu,代表上下文菜单,上下文菜单无须使用Menubar盛装。

MenuMenuItem的构造器都可接收一个字符串参数,该字符串作为其对应菜单、菜单项上的标签文本。

除此之外,MenuItem还可以接收一个MenuShortcut对象,该对象用于指定该菜单的快捷键。

快捷键

MenuShortcut类使用虚拟键代码(而不是字符)来创建快捷键。

Ctrl快捷键

例如,Ctrl+A(通常都以Ctrl键作为快捷键的辅助键)快捷方式通过以下代码创建:

1
MenuShortcut ms== new MenuShortcut(KeyEvent.VK_A);

Ctrl+Shift快捷键

如果该快捷键还需要Shift键的辅助,则可使用如下代码:

1
MenuShortcut ms = new MenuShortcut(KeyEvent.VK_A, true);

有时候程序还希望对某个菜单进行分组,将功能相似的菜单分成一组,此时需要使用菜单分隔符,AWT中添加菜单分隔符有如下两种方法。

  • 调用Menu对象的addSeparator()方法来添加菜单分隔线
  • 使用添加new Menuitem("-")的方式来添加菜单分隔线

创建了MenuitemMenuMenuBar对象之后,

  • 调用Menuadd()方法将多个Menuitem组合成菜单(也可将另一个Menu对象组合进来,从而形成二级菜单),
  • 再调用MenuBaradd()方法将多个Menu组合成菜单条,
  • 最后调用Frame对象的setMenuBar方法为该窗口添加菜单条

程序示例 为窗体添加菜单条

下面程序示范了为窗口添加菜单的完整程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import java.awt.*;
import java.awt.event.*;

public class SimpleMenu {
private Frame f = new Frame("测试");
private MenuBar mb = new MenuBar();
Menu file = new Menu("文件");
Menu edit = new Menu("编辑");
MenuItem newItem = new MenuItem("新建");
MenuItem saveItem = new MenuItem("保存");
// 创建exitItem菜单项,指定使用 Ctrl+X 快捷键
MenuItem exitItem = new MenuItem("退出", new MenuShortcut(KeyEvent.VK_X));
CheckboxMenuItem autoWrap = new CheckboxMenuItem("自动换行");
MenuItem copyItem = new MenuItem("复制");
MenuItem pasteItem = new MenuItem("粘贴");
Menu format = new Menu("格式");
// 创建commentItem菜单项,指定使用 Ctrl+Shift+/ 快捷键
MenuItem commentItem = new MenuItem("注释", new MenuShortcut(KeyEvent.VK_SLASH, true));
MenuItem cancelItem = new MenuItem("取消注释");
private TextArea ta = new TextArea(6, 40);

public void init() {
// 以Lambda表达式创建菜单事件监听器
ActionListener menuListener = e -> {
String cmd = e.getActionCommand();
ta.append("单击“" + cmd + "”菜单" + "\n");
if (cmd.equals("退出")) {
System.exit(0);
}
};
// 为commentItem菜单项添加事件监听器
commentItem.addActionListener(menuListener);
exitItem.addActionListener(menuListener);
// 为file菜单添加菜单项
file.add(newItem);
file.add(saveItem);
file.add(exitItem);
// 为edit菜单添加菜单项
edit.add(autoWrap);
// 使用addSeparator方法来添加菜单分隔线
edit.addSeparator();
edit.add(copyItem);
edit.add(pasteItem);
// 为format菜单添加菜单项
format.add(commentItem);
format.add(cancelItem);
// 使用添加new MenuItem("-")的方式添加菜单分隔线
edit.add(new MenuItem("-"));
// 将format菜单组合到edit菜单中,从而形成二级菜单
edit.add(format);
// 将file、edit菜单添加到mb菜单条中
mb.add(file);
mb.add(edit);
// 为f窗口设置菜单条
f.setMenuBar(mb);
// 以匿名内部类的形式来创建事件监听器对象
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.add(ta);
f.pack();
f.setVisible(true);
}

public static void main(String[] args) {
new SimpleMenu().init();
}
}

上面程序中的菜单既有复选框菜单项菜单分隔符,也有二级菜单,并为两个菜单项添加了快捷键,为commentItem,exitltem两个菜单项添加了事件监听器。

运行该程序,并按“Ctrl+Shift+/”快捷键,将看到如图11.25所示的窗口

这里有一张图片

AWT的菜单组件不能创建图标菜单,如果希望创建带图标的菜单,则应该使用Swing的菜单组件:JMenuBarJMenuMenuItemPopupMenu组件。Swing的菜单组件和AWT的菜单组件的用法基本相似,读者可参考本程序学习使用Swing的菜单组件。

11.6.2 右键菜单

右键菜单使用PopupMenu对象表示,创建右键菜单的步骤如下:

  • 创建PopupMenu的实例。
  • 创建多个Menuitem的多个实例,依次将这些实例加入PopupMenu中。
  • PopupMenu加入到目标组件中。
  • 为需要出现上下文菜单的组件编写鼠标监听器,当用户释放鼠标右键时弹出右键菜单。

程序示例 右键菜单

下面程序创建了一个右键菜单,该右键菜单就是“借用”前面Simplemenuedit菜单下的所有菜单项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import java.awt.*;
import java.awt.event.*;

public class PopupMenuTest {
private TextArea ta = new TextArea(4, 30);
private Frame f = new Frame("测试");
PopupMenu pop = new PopupMenu();
CheckboxMenuItem autoWrap = new CheckboxMenuItem("自动换行");
MenuItem copyItem = new MenuItem("复制");
MenuItem pasteItem = new MenuItem("粘贴");
Menu format = new Menu("格式");
// 创建commentItem菜单项,指定使用 Ctrl+Shift+/ 快捷键
MenuItem commentItem = new MenuItem("注释", new MenuShortcut(KeyEvent.VK_SLASH, true));
MenuItem cancelItem = new MenuItem("取消注释");

public void init() {
// 以Lambda表达式创建菜单事件监听器
ActionListener menuListener = e -> {
String cmd = e.getActionCommand();
ta.append("单击“" + cmd + "”菜单" + "\n");
if (cmd.equals("退出")) {
System.exit(0);
}
};
// 为commentItem菜单项添加了事件监听器。
commentItem.addActionListener(menuListener);
// 为pop菜单添加菜单项
pop.add(autoWrap);
// 使用addSeparator方法来添加菜单分隔线
pop.addSeparator();
pop.add(copyItem);
pop.add(pasteItem);
// 为format菜单添加菜单项
format.add(commentItem);
format.add(cancelItem);
// 使用添加new MenuItem("-")的方式添加菜单分隔线
pop.add(new MenuItem("-"));
// 将format菜单组合到pop菜单中,从而形成二级菜单
pop.add(format);
final Panel p = new Panel();
p.setPreferredSize(new Dimension(300, 160));
// 向p窗口中添加PopupMenu对象
p.add(pop);
// 添加鼠标事件监听器
p.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
// 如果释放的是鼠标右键
if (e.isPopupTrigger()) {
pop.show(p, e.getX(), e.getY());
}
}
});
f.add(p);
f.add(ta, BorderLayout.NORTH);
// 以匿名内部类的形式来创建事件监听器对象
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.pack();
f.setVisible(true);
}

public static void main(String[] args) {
new PopupMenuTest().init();
}
}

运行上面程序,会看到如图11.26所示的窗口:

这里有一张图片

为什么Windows上的AWT的TextArea组件有默认的右键菜单

AWT并没有为GUI组件提供实现,它仅仅是调用运行平台的GUI组件来创建和平台一致的对等体。假设程序在Windows平台上运行,则程序中的TextArea实际上是Windows的多行文本域组件的对等体,具有和它相同的行为,所以该TextArea默认就具有右键菜单。