1. 菜单栏、菜单、菜单项之间的关系:

    1) 菜单栏(MenuBar)就是窗口中常见的顶层菜单栏,包含文件、编辑、格式等等子菜单的菜单条,即包含菜单的容器;

    2) 菜单(Menu)是必定包含菜单项或者菜单(嵌套包含菜单,也叫子菜单)的容器;

    3) 菜单项(MenuItem)即最小单位,即可以单击产生特效的菜单按钮,存在于菜单中的元素;

!!注意:Menu是MenuItem的子类,因此Menu是一种特殊的菜单项,可以作为Menu自己中的元素,作为二级菜单出现;

!!在AWT中Menu在MenuBar中是正常的(只有文本标签显示出来),而Menu在Menu中则必定是二级子菜单,除了显示文本标签之外,必定显示一个右角标,表示这是一个二级菜单,可以再展开一摞菜单项;


2. 如何制作菜单:

    1) 首先需要一个菜单栏,使用MenuBar的构造器:MenuBar(); // 只有一个默认的无参构造器

!!将菜单栏和窗口绑定在一起使用Frame的setMenuBar方法:public void Frame.setMenuBar(MenuBar mb); // 指定菜单栏参数

    2) 接着需要在菜单栏中添加菜单(一级子菜单):

         i. 创建子菜单,使用Menu的构造器:Menu(String label); // 指定菜单的文本标签

         ii. 将子菜单加入到菜单栏中,使用MenuBar的add方法(就跟普通容器一样添加):Menu MenuBar.add(Menu m); // 返回的是加入的子菜单

    3) 为子菜单添加菜单项:

         i. 首先要创建菜单项,使用MenuItem的构造器:MenuItem(String label); // 菜单项的文本标签

         ii. 有时需要为菜单项指定快捷键,那么就需要使用可以指定快捷键的构造器:MenuItem(String label, MenuShortcut s); // MenuShortcut是菜单项快捷键类

             a. MenuShortcut构造器:MenuShortcut(int key); // 默认Ctrl+key的组合作为快捷键

             b. 加Shift组合:MenuShortcut(int key, boolean useShiftModifier); // 第二个参数如果为true表示使用Ctrl+Shift+key的组合作为快捷键;

!!注意快捷键和加速键的区别:快捷键必须要使用Ctrl(Shift可选),而加速键必须要使用Alt;

!!key是KeyEvent类定义的静态常量,全部用虚拟键表示,比如'X'就是KeyEvent.VK_X,'/'就是KeyEvent.VK_SLASH,具体是什么可以翻阅手册;

          iii. 使用Menu的add方法将菜单项或者下级子菜单加入其中:MenuItem Menu.add(MenuItem mi); // 返回的是加入的菜单项

!!由于Menu是MenuItem的子类,因此还是使用该方法添加下级子菜单;

!!如果加的是子菜单那么会显示出一个右角标!!表示这是一个下级子菜单,可以进一步展开;

          iv. 示例:Menu m = new Menu("File"); m.add(new MenuItem("Copy", new MenuShortcut(KeyEvent.VK_C)); // 创建了一个Ctrl+C的快捷键菜单项“复制”

!!添加下级子菜单和其菜单项的步骤重复3)即可,仅仅就是简单的嵌套;


3. 菜单分隔符以及添加菜单项的更简单的方法:

    1) 有时候需要将子菜单中的各个菜单项按照逻辑分类,此时可以用分隔符将类型相同的菜单项分到一组去;

    2) 有三种方法可以做到:

         i. void Menu.addSeparator();

         ii. void Menu.add(String label); // 该方法可以直接添加菜单项,根据文本标签添加菜单项,其实现

public void add(String label) {
    add(new MenuItem(label));
}
!!可以看到这是对add方法的重载;

!!这种方法直接add("-");就添加了一条分隔符

         iii. void Menu.add(MenuItem mi); // 直接add(new MenuItem("-");就可以添加分隔符

    3) 一般推荐方法ii.,最为简洁;


4. 菜单事件处理:

    1) 至于单击菜单弹出子菜单等工作都由AWT自动完成,无需程序员管理;

    2) 用户需要自己处理的只有菜单项单击事件,该事件属于ActionEvent类型;

    3) 但是ActionListener接口只有actionPerformed一个方法,因此要监控所有菜单项的单击事件就必须在该方法中加以判断;

    4) 判断是那个菜单项的单击事件还是很简单的,只需要调用e.getActionCommand方法就能获取发生事件的菜单项上的标签文本了,示例:

ActionListener menuListener = e -> {
	String cmd = e.getActionCommand();
	ta.append("Click '" + cmd + "' menu item.\n");
	if (cmd.equals("Exit")) {
		System.exit(0);
	}
};
    5) 最后只要将监听器注册给菜单项即可:public synchronized void MenuItem.addActionListener(ActionListener l);


5. 复选菜单项:

    1) CheckboxMenuItem,即最左侧带一个复选勾菜单项,单击一次打钩并关闭菜单,再单击一次取消打钩并关闭菜单;

    2) 构造器:CheckboxMenuItem(String label); // 就只有指定标签文本的版本

    3) 添加这种菜单项的操作和普通的MenuItem一模一样,ChecboxMenuItem是MenuItem的子类;

!!注意:复选菜单项不产生ActionEvent事件,因此不能用ActionListener来监控它;


6. 示例:

public class AwtTest {

	public void init() {
		Frame f = new Frame("Menu Test");
			MenuBar mb = new MenuBar(); f.setMenuBar(mb);
				Menu file = new Menu("File"); mb.add(file);
					MenuItem newItem = new MenuItem("New"); file.add(newItem);
					MenuItem saveItem = new MenuItem("Save"); file.add(saveItem);
					MenuItem exitItem = new MenuItem("Exit", new MenuShortcut(KeyEvent.VK_X)); file.add(exitItem);
				Menu edit = new Menu("Edit"); mb.add(edit);
					CheckboxMenuItem autoWrap = new CheckboxMenuItem("Auto wrap"); edit.add(autoWrap);
					edit.addSeparator();
					MenuItem copyItem = new MenuItem("Copy"); edit.add(copyItem);
					MenuItem pasteItem = new MenuItem("Paste"); edit.add(pasteItem);
					edit.add(new MenuItem("-"));
					Menu format = new Menu("Format"); edit.add(format);
						MenuItem commentItem = new MenuItem("Comment", new MenuShortcut(KeyEvent.VK_SLASH, true));
							format.add(commentItem);
						MenuItem cancelItem = new MenuItem("Cancel comment"); format.add(cancelItem);
			TextArea ta = new TextArea(6, 40); f.add(ta);
			
			ActionListener menuListener = e -> {
				String cmd = e.getActionCommand();
				ta.append("Click '" + cmd + "' menu item.\n");
				if (cmd.equals("Exit")) {
					System.exit(0);
				}
			};
			newItem.addActionListener(menuListener);
			saveItem.addActionListener(menuListener);
			exitItem.addActionListener(menuListener);
			// autoWrap.addActionListener(menuListener); // CheckboxMenuItem不触发ActionEvent!!
			copyItem.addActionListener(menuListener);
			pasteItem.addActionListener(menuListener);
			commentItem.addActionListener(menuListener);
			cancelItem.addActionListener(menuListener);
			f.addWindowListener(new WindowAdapter() {
				@Override
				public void windowClosing(WindowEvent e) {
					// TODO Auto-generated method stub
					// super.windowClosing(e);
					System.exit(0);
				}
			});
			
			f.pack();
			f.setVisible(true);
	}
	
	public static void main(String[] args) {
		new AwtTest().init();
	}

}


!!!注意:AWT的菜单不支持自制菜单,如果要像MFC那样可以自己画菜单项就必须使用Swing组件了,而Swing组件的用法完全基于AWT的,方法都非常类似;

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐