使用的教材是java核心技术卷1,我将跟着这本书的章节同时配合视频资源来进行学习基础java知识。
Swing还提供了一些其他种类的用户界面元素,下拉式菜单就是GUI应用程序中很常见的一种。位于窗口顶部的菜单栏(menu bar)包括了下拉菜单的名字。点击一个名字就可以打开包含菜单项(menu items)和子菜单(submenus)的菜单。当用户点击菜单项时,所有的菜单都会被关闭并且将一条消息发送给程序。
创建菜单是一件非常容易的事情。首先要创建一个菜单栏:
JMenuBar menuBar = new JMenuBar();
菜单栏是一个可以添加到任何位置的组件。通常放置在框架的顶部。可以调用 setJMenuBar方法将菜单栏添加到框架上:
frame.setJMenuBar(menuBar);
需要为每个菜单建立一个菜单对象:
JMenue ditMenu=new JMenu("Edit");
然后将顶层菜单添加到菜单栏中:
menuBar.add(editMenu);
向菜单对象中添加菜单项、分隔符和子菜单:
JMenuItem pasteltem=new JMenuItem("Paste");
editMenu.add(pasteltem);
editMenu.addSeparator();
JMenu optionsMenu=...;//a submenu
editMenu.add(optionsMenu);
当用户选择菜单时,将触发一个动作事件。这里需要为每个菜单项安装一个动作监听器。
ActionListener listener =...;
pasteItem.addActionListener(listener);
可以使用JMenu.add(Striiigs)方法将菜单项插入到菜单的尾部,例如:
editMenu.add("Paste");
Add方法返回创建的子菜单项。可以采用下列方式获取它,并添加监听器:
JMenuItem pasteltem=editMenu.add("Paste");
pasteltem.addActionListener(listener);
在通常情况下,菜单项触发的命令也可以通过其他用户界面元素(如工具栏上的按钮)激活。之前已经看到了如何通过Action对象来指定命令。通常,采用扩展抽象类AbstractAction来定义一个实现Action接口的类。这里需要在AbstractAction对象的构造器中指定菜单项标签并且覆盖actionPerformed方法来获得菜单动作处理器。例如:
Action exitAction = new AbstractAction("Exit")//menu item text goes here
{
public void actionPerformed(ActionEvent event)
{
//action code goes here
System.exit(0);
}
};
然后将动作添加到菜单中:
JMenuItem exitltem = fileMenu.add(exitAction);
这个命令利用动作名将一个菜单项添加到菜单中。这个动作对象将作为它的监听器。上面这条语句是下面两条语句的快捷形式:
JMenuItem exitltem = new JMenuItem(exitAction);
fileMenu.add(exitltem);
菜单项与按钮很相似。实际上,JMenuItem类扩展了AbstractButton类。与按钮一样,菜单可以包含文本标签、图标,也可以两者都包含。既可以利用JMenuItem(Striiig,Icon)或者JMenuItem(Icon)构造器为菜单指定一个图标,也可以利用JMenuItem类中的setlcon方法(继承自AbstractButton类)指定一个图标。例如:
JMenuItem cutltem = new JMenuItem("Cut", new Imagelcon("cut.gif"));
在默认情况下,菜单项的文本被放置在图标的右侧。如果喜欢将文本放置在左侧,可以调用JMenuItem类中的setHorizontalTextPosition方法(继承自AbstractButton类)设置。例如:
cutltem.setHorizontalTextPosition(SwingConstants.LEFT);
这个调用把菜单项文本移动到图标的左侧。也可以将一个图标添加到一个动作上:
cutAction.putValue(Action.SMALL.ICON, new Imagelcon("cut.gif"));
当使用动作构造菜单项时,Action.NAME值将会作为菜单项的文本,而Action.SMALL_ICON将会作为图标。另外,可以利用AbstractAction构造器设置图标:
cutAction = new AbstractAction("Cut", new Imagelcon("cut.gif"))
{
public void actionPerformed(ActionEvent event)
{
...
}
};
复选框和单选钮菜单项在文本旁边显示了一个复选框或一个单选钮。当用户选择一个菜单项时,菜单项就会自动地在选择和未选择间进行切换。除了按钮装饰外,同其他菜单项的处理一样。
例如,下面是创建复选框菜单项的代码:
JCheckBoxHenuItem readonlyltem=new JCheckBoxMenuItem ( "Read-only") ;
optionsMenu.add ( readonlyltem) ;
单选钮菜单项与普通单选钮的工作方式一样,必须将它们加人到按钮组中。当按钮组中的一个按钮被选中时,其他按钮都自动地变为未选择项。
ButtonGroup group=new ButtonGroup();
JRadioButtonMenuItem insertltem= new]RadioButtonMenuItem ("Insert") ;
insertltem.setSelected ( true) ;
JRadioButtonMenuItem overtypeltem=new JRadioButtonMenuItem ( "Overtype");
group.add ( insertltem) ;
group.add ( overtypeltem) ;
optionsMenu.add ( insertltem) ;
optionsMenu.add ( overtypeltem) ;
使用这些菜单项,不需要立刻得到用户选择菜单项的通知。而是使用isSelected方法来测试菜单项的当前状态(当然,这意味着应该保留一个实例域保存这个菜单项的引用)。使用setSelected方法设置状态。
弹出菜单(pop-up menu) 是不固定在菜单栏中随处浮动的菜单。创建一个弹出菜单与创建一个常规菜单的方法类似,但是弹出菜单没有标题。
JPopupMenu popup = new JPopupMenu();
然后用常规的方法添加菜单项:
JMenuItem item = new JMenuItem("Cut");
item.addActionListener(listener);
popup.add(item);
弹出菜单并不像常规菜单栏那样总是显示在框架的顶部,必须调用show方法菜单才能显示出来。调用时需要给出父组件以及相对父组件坐标的显示位置。例如:
popup.show(panel,x,y);
通常,当用户点击某个鼠标键时弹出菜单。这就是所谓的弹出式触发器(pop-uptrigger)o在Windows或者Linux中,弹出式触发器是鼠标右键。要想在用户点击某一个组件时弹出菜单,需要按照下列方式调用方法:
component.setComponentPopupMenu(popup);
偶尔会遇到在一个含有弹出菜单的组件中放置一个组件的情况。这个子组件可以调用下列方法继承父组件的弹出菜单。调用:
child.setlnheritsPopupMenu(true);
对于有经验的用户来说,通过快捷键来选择菜单项会感觉更加便捷。可以通过在菜单项的构造器中指定一个快捷字母来为菜单项设置快捷键:
JMenuItem aboutltem = new JHenuItem("About",'A');
快捷键会自动地显示在菜单项中,并带有一条下划线,菜单项中的标签为“About”,字母A带有一个下划线。当显示菜单时,用户只需要按下“A”键就可以这个选择菜单项(如果快捷字母没有出现在菜单项标签字符串中,同样可以按下快捷键选择菜单项,只是快捷键没有显示出来。很自然,这种不可见的快捷键没有提示效果)。
有时候不希望在菜单项的第一个快捷键字母下面加下划线。例如,如果在菜单项“SaveAs”中使用快捷键“A”,则在第二个“A”(SaveAs)下面加下划线更为合理。可以调用setDisplayedMnemonicIndex方法指定希望加下划线的字符。
如果有一个Action对象,就可以把快捷键作为Action.MNEMONIC_KEY的键值添加到对象中。如:
cutAction.putValue(Action,MNEMONIC_KEY, new Integer('A'));
只能在菜单项的构造器中设定快捷键字母,而不是在菜单构造器中。如果想为菜单设置快捷键,需要调用setMnemonic方法:
JMenu helpMenu = new JMenu("Help");
helpMenu.setMnemonic('H');
可以同时按下ALT键和菜单的快捷键来实现在菜单栏中选择一个顶层菜单的操作。例如:按下ALT+H可以从菜单中选择Help菜单项。可以使用快捷键从当前打开的菜单中选择一个子菜单或者菜单项。而加速器是在不打开菜单的情况下选择菜单项的快捷键。例如:很多程序把加速器CTRL+O和CTRL+S关联到File菜单中的Open和Save菜单项。可以使用setAccelerator将加速器键关联到一个菜单项上。这个方法使用Keystroke类型的对象作为参数。例如:下面的调用将加速器CTRL+O关联到Openltem菜单项。
openItem.setAccelerator(KeyStroke.getKeyStroke("ctrl O"));
当用户按下加速器组合键时,就会自动地选择相应的菜单项,同时激活一个动作事件,这与手工地选择这个菜单项一样。加速器只能关联到菜单项上,不能关联到菜单上。加速器键并不实际打开菜单。它将直接地激活菜单关联的动作事件。
从概念上讲,把加速器添加到菜单项与把加速器添加到Swing组件上所使用的技术十分类似。但是,当加速器添加到菜单项时,对应的组合键就会自动地显示在相应的菜单上。在Windows下,ALT+F4用于关闭窗口。但这不是Java程序设定的加速键.这是操作系统定义的快捷键。这个组合键总会触发活动窗口的WindowClosing事件,而不管菜单上是否有Close菜单项。
在有些时候,某个特定的菜单项可能只能够在某种特定的环境下才可用。例如,当文档以只读方式打开时,Save菜单项就没有意义s当然,可以使用JMemremove方法将这个菜单项从菜单中删掉,但用户会对菜单内容的不断变化感到奇怪。然而,可以将这个菜单项设为禁用状态,以便屏蔽掉这些暂时不适用的命令。被禁用的菜单项被显示为灰色,不能被选择它。启用或禁用菜单项需要调用setEnabled方法:
saveltem.setEnabled ( false):
启用和禁用菜单项有两种策略。每次环境发生变化就对相关的菜单项或动作调用setEnabled。例如:只要当文档以只读方式打开,就禁用Save和SaveAs菜单项。另一种方法是在显示菜单之前禁用这些菜单项。这里必须为“菜单选中” 事件注册监听器。javax.swing.event 包定义了 MenuListener 接口,它包含三个方法:
void menuSelected(MenuEvent event)
void menuDeselected(MenuEvent event)
void menuCanceled(MenuEvent event)
由于在菜单显示之前调用menuSelected方法,所以可以在这个方法中禁用或启用菜单项。下面代码显示了只读复选框菜单项被选择以后,如何禁用Save和SaveAs动作。
public void menuSelected(MenuEvent event)
{
saveAction.setEnabled(!readonlyltem.isSelected());
saveAsAction.setEnabled(!readonlyltem.isSelected());
}
下面的程序是创建一组菜单的示例程序。这个程序演示了本节介绍的所有特性,包括:嵌套菜单、禁用菜单项、复选框和单选钮菜单项、弹出菜单以及快捷键和加速器。
/**
*@author zzehao
*/
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
public class MenuFrame extends JFrame
{
private static final int DEFAULT_WIDTH = 300;
private static final int DEFAULT_HEIGHT = 200;
private Action saveAction;
private Action saveAsAction;
private JCheckBoxMenuItem readonlyItem;
private JPopupMenu popup;
//动作
class TestAction extends AbstractAction
{
public TestAction( String name )
{
super( name );
}
@Override
public void actionPerformed(ActionEvent e)
{
System.out.println( getValue( Action.NAME ) + " selected." );
}
}
public MenuFrame()
{
setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);
//File是一级菜单
JMenu fileMenu = new JMenu("File");
//File下面的二级菜单有:New, Open, Save, Save As, Exit
fileMenu.add(new TestAction("New"));
//给Open菜单项添加快捷键
JMenuItem openItem = fileMenu.add(new TestAction("Open"));
openItem.setAccelerator(KeyStroke.getKeyStroke("ctrl 0"));
//将一个分隔符行添加到File菜单中
fileMenu.addSeparator();
//给Save菜单项添加快捷键
saveAction = new TestAction("Save");
JMenuItem saveItem = fileMenu.add(saveAction);
saveItem.setAccelerator(KeyStroke.getKeyStroke("ctrl S"));
//添加Save As菜单项
saveAsAction = new TestAction("Save As");
fileMenu.add(saveAsAction);
fileMenu.addSeparator();
//添加Exit菜单项
fileMenu.add(new AbstractAction("Exit") {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
//==============================================
//readonlyItem是复选框菜单项
readonlyItem = new JCheckBoxMenuItem( "Read-only" );
readonlyItem.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
//表示勾选了Read-only复选框,就不能点击Save或者Save As菜单项了
boolean saveOk = !readonlyItem.isSelected();
saveAction.setEnabled(saveOk);
saveAsAction.setEnabled(saveOk);
}
});
//group是单选按钮组;其中有Insert和Overtype两个单选按钮,即选了其中一个,另一个就会失选; 设定insert初始被选中
ButtonGroup group = new ButtonGroup();
JRadioButtonMenuItem isertItem = new JRadioButtonMenuItem("Insert");
isertItem.setSelected(true);
JRadioButtonMenuItem overtypeItem = new JRadioButtonMenuItem("Overtype");
group.add(isertItem);
group.add(overtypeItem);
//Edit是一级菜单项,下面包括了Cut, Copy, Paste, Options 4个二级菜单项
//Options是二级菜单项,下面又包括readonlyItem,isertItem,overtypeItem3个三级菜单项
Action cutAction = new TestAction("Cut");
cutAction.putValue(Action.SMALL_ICON, new ImageIcon("cut.gif"));
Action copyAction = new TestAction("Copy");
copyAction.putValue(Action.SMALL_ICON, new ImageIcon("copy.gif"));
Action pasteAction = new TestAction("Paste");
pasteAction.putValue(Action.SMALL_ICON, new ImageIcon("paste.gif"));
JMenu editMenu = new JMenu("Edit");
editMenu.add(cutAction);
editMenu.add(copyAction);
editMenu.add(pasteAction);
JMenu optionMenu = new JMenu("Options");
optionMenu.add(readonlyItem);
optionMenu.addSeparator();;
optionMenu.add(isertItem);
optionMenu.add(overtypeItem);
editMenu.addSeparator();
editMenu.add(optionMenu);
//=============================================
//Help是一级菜单项,下面有Index, About两个二级菜单项
JMenu helpMenu = new JMenu("Help");
helpMenu.setMnemonic('H');//给H字母添加快捷键;可以ALT+H唤醒Help菜单
JMenuItem indexItem = new JMenuItem("Index");
indexItem.setMnemonic('I');
helpMenu.add(indexItem);
Action aboutAction = new TestAction("About");
//给字母A添加快捷键,即直接按A就能唤醒About菜单项;前提是Help已经唤醒
aboutAction.putValue(Action.MNEMONIC_KEY, new Integer('A'));
helpMenu.add(aboutAction);
//菜单栏,将所有一级菜单项放入其中
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
menuBar.add(fileMenu);
menuBar.add(editMenu);
menuBar.add(helpMenu);
//弹出菜单;/点击鼠标右键,弹出菜单
popup = new JPopupMenu();
popup.add(cutAction);
popup.add(copyAction);
popup.add(pasteAction);
JPanel panel = new JPanel();
//点击鼠标右键,弹出菜单
panel.setComponentPopupMenu(popup);
add(panel);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
JFrame frame = new MenuFrame();//初始化窗口
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置:关闭窗口,则程序退出
frame.setVisible(true);//显示窗口
}
});
}
}
运行的结果是: