在java Swing编程过程中经常需要处理键盘事件例如处理快捷键等这里就介绍如何定义键盘事件以及如何处理这些事件
在jdk中分别针对Jcomponent和Text类的对象定制了不同的处理键盘事件的方法在Jcomponent中定义了registerKeyboardAction方法使用这个方法来将需要处理的键盘事件以及处理事件的行为绑定在一起Text类中具有keymap对象同Jcomponent中的处理方法类似这个对象保存着需要处理的键盘事件和对应的行为
而在jdk中使用一种新的方法来处理键盘事件它将jdk的两种方法整合在一起不需要区分被处理的是Jcomponent还是Text类型的组件它定义了两个新的类InputMap和ActionMap他们均是简单的表或映射一个InputMap将一个Keystroke对应到一个对象ActionMap将一个对象对应到一个行为(Action)通常InputMap中KeyStroke所对应的对象是一个字符串通过这个字符串可以在ActionMap中查找到相应的行为
InputMap和ActionMap中均有put方法InputMap的put方法可以将Keystroke对应到一个对象而ActionMap的put方法可以将一个对象对应到一个行为
在每一个Jcomponent组件中会有三个缺省的InputMap和一个缺省的ActionMap他们可以通过调用getInputMap(int condition)和getActionMap()得到三个InputMap分别是当组件本身拥有焦点时的InputMap(WHEN_FOCUSED)当组件的祖先拥有焦点时的InputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)和组件所在的窗体具有焦点时的InputMap(WHEN_IN_FOCUSED_WINDOW)(括号内表示为了得到这些InputMap应该在getInputMap中设置的参数)以下分别说明这三种InputMap
组件本身拥有焦点时的InputMap当组件拥有焦点时键盘按键按下则java在这个InputMap中查找键盘事件所对应的KeyStroke对象
组件的祖先拥有焦点时的InputMap当组件的祖先拥有焦点时键盘按键按下则java查找这个InputMap
组件所在的窗口拥有焦点时的InputMap当组件所在的窗口具有焦点时键盘按键按下则java查找这个InputMap
当一个键被按下这个事件被转化成一个KeyStroke对象java会查找这个Jcomponent的相应InputMap(例如当组件的祖先具有焦点时java就查找这个Jcomponent的祖先拥有焦点的InputMap)中是否有这个KeyStroke如果有取出它所对应的对象(通常是字符串)利用这个对象在这个Jcomponent的ActionMap中查找如果找到对应的行为(Action)则java执行这个行为的actionPerformed方法(随后介绍这个方法)从而达到处理键盘事件的目的
每一个InputMap可以具有parent属性这个属性的值是一个InputMap当在一个InputMap中查找不到键盘事件的KeyStroke时java会自动在它的parent属性指定的InputMap中查找依次向上查找直至找到使用parent的好处是当有一些固定的不希望用户进行改动的键盘映射可以存放在parent属性所指定的InputMap中从而避免被意外修改另外可以将多个Jcomponent的缺省InputMap设置具有相同的parent使得可以共享一些键盘绑定的设置可以通过InputMap类的setparent()方法设置它的parent属性ActionMap也具有相同的parent属性使用方法也相同
以上是如何将一个键盘事件对应到一个行为以下就简单介绍行为(Action)
行为是一个实现了Action接口的类在Action接口中定义了个方法其中最关键的是actionPerformed()方法这个方法描述了这个行为的具体操作过程其他几个方法包括setEnabledisEnabledputValuegetValueaddPropertyChangeListener和removePropertyChangeListener方法他们分别用来设置行为是否可用判断行为可用的状态设置和取得行为的一些属性最后两个方法用来允许其他对象在行动对象的属性发生变化后得到通知
通常我们使用一个实现了Action接口的大部分方法的抽象类AbstractAction类作为基类重载actionPerformed方法以实现我们的行为
我们用一个例子来具体说明如何进行实际的操作
首先编写一个具体的行为对指定的键盘事件进行处理
public class TextAction extends AbstractAction
{
private String a;
public TextAction(String a)
{ thisa = a; }
public void actionPerformed(ActionEvent parm)
{
String b = parmgetActionCommand(); //得到行为的命令字符串
Systemoutprintln(command=+b);
Systemoutprintln(prompt=+thisa);
}
}
建立四个TextAction对象
TextAction whenFocusSon = new TextAction(focus son);
TextAction whenFocusFather = new TextAction(focus father);
TextAction window = new TextAction(window);
TextAction ancestor = new TextAction(ancestor);
随后在一个窗体中加入两个面板名为sonPanel和parentPanel使得parentPanel是sonPanel的祖先并在sonPanel中加入一个名为son的button在parentPanel中加入名为parent的button在fatherPanel外加入几个button
得到son组件的三个InputMap并创建一个名为focusFatherIm的InputMap使得这个InputMap成为focusIm的parent
//get default inputMap (when focus inputmap) and set a parent InputMap
focusIm = songetInputMap();
focusFatherIm = new InputMap();
focusImsetParent(focusFatherIm);
//get WHEN_ANCESTOR_OF_FOCUSED_COMPONENT inputMap
ancestorIm = songetInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
//get WHEN_IN_FOCUSED_WINDOW inputMap
windowIm = songetInputMap(WHEN_IN_FOCUSED_WINDOW);
在这些InputMap中分别加入键盘绑定
focusImput(KeyStrokegetKeyStroke(f)actionFocusSon);
focusFatherImput(KeyStrokegetKeyStroke(F)actionFocusFather);
ancestorImput(KeyStrokegetKeyStroke(a)actionAncestor);
windowImput(KeyStrokegetKeyStroke(w)actionWindow);
得到son组件的缺省的ActionMap并将已经建立的行为与特定的对象(字符串)进行绑定
am = songetActionMap();
amput(actionFocusSonwhenFocusSon);
amput(actionFocusFatherwhenFocusFather);
amput(actionAncestorancestor);
amput(actionWindowwindow);
运行程序及其相应结果
单击son按钮这时如果按下fFaw程序均会有相应的输出这是因为此时的焦点在son按钮上而son按钮组件的三个InputMap都是有效的所以他们对应的事件都会发生
单击parent按钮这时按下w程序会有相应的输出而按下fFa程序没有反应这是因为parent按钮具有焦点这个按钮不是son按钮的祖先而son所在的窗口具有焦点所以只有组件所在窗口具有焦点的InputMap是有效的
单击其他的按钮(parentPanel外的按钮)这时按下w程序会有相应的输出而按下fFa程序没有反应这是因为这些按钮具有焦点他们不是son按钮的祖先而son所在的窗口具有焦点所以只有组件所在窗口具有焦点的InputMap是有效的
附主要程序代码
import javaawt*;
import javaxswing*;
import comborlandjbcllayout*;
import javaawteventActionEvent;
import javaawteventActionListener;
import comsunjavaswingplafmotif*;
public class EventPanel extends JPanel implements ActionListener
{
JButton btnYellow = new JButton();
JButton btnBlue = new JButton();
JButton btnRed = new JButton();
JPanel parentPanel = new JPanel();
JPanel sonPanel = new JPanel();
XYLayout xYLayout = new XYLayout();
JButton son = new JButton();
JButton parent = new JButton();
public EventPanel()
{
try{
jbInit();
}catch(Exception ex)
{ exprintStackTrace(); }
}
void jbInit() throws Exception
{
btnYellowsetText(Yellow);
btnYellowsetBounds(new Rectangle( ));
thissetLayout(null);
btnBluesetBounds(new Rectangle( ));
btnBluesetText(Blue);
btnRedsetBounds(new Rectangle( ));
btnRedsetText(Red);
parentPanelsetBorder(BorderFactorycreateRaisedBevelBorder());
parentPanelsetBounds(new Rectangle( ));
parentPanelsetLayout(xYLayout);
sonPanelsetBorder(BorderFactorycreateLoweredBevelBorder());
sonsetText(son);
parentsetText(parent);
thisadd(btnYellow null);
thisadd(btnBlue null);
thisadd(btnRed null);
thisadd(parentPanel null);
parentPaneladd(sonPanel new XYConstraints( ));
sonPaneladd(son null);
parentPaneladd(parent new XYConstraints(