Java Swing中键盘的处理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java Swing中键盘的处理相关的知识,希望对你有一定的参考价值。
参考技术A在jdk 中 分别针对Jponent和Text类的对象定制了不同的处理键盘事件的方法 在Jponent中 定义了registerKeyboardAction方法 使用这个方法来将需要处理的键盘事件以及处理事件的行为绑定在一起 Text类中具有keymap对象 同Jponent中的处理方法类似 这个对象保存著需要处理的键盘事件和对应的行为
而在jdk 中 使用一种新的方法来处理键盘事件 它将jdk 的两种方法整合在一起 不需要区分被处理的是Jponent还是Text类型的组件 它定义了两个新的类 InputMap和ActionMap 他们均是简单的表或映射 一个InputMap将一个Keystroke对应到一个对象 ActionMap将一个对象对应到一个行为(Action) 通常InputMap中KeyStroke所对应的对象是一个字符串 通过这个字符串可以在ActionMap中查找到相应的行为
InputMap和ActionMap中均有put方法 InputMap的put方法可以将Keystroke对应到一个对象 而ActionMap的put方法可以将一个对象对应到一个行为
在每一个Jponent组件中 会有三个缺省的InputMap和一个缺省的ActionMap 他们可以通过调用getInputMap(int condition)和getActionMap()得到 三个InputMap分别是当组件本身拥有焦点时的InputMap(WHEN_FOCUSED) 当组件的祖先拥有焦点时的InputMap(WHEN_ANCESTOR_OF_FOCUSED_PONENT)和组件所在的窗体具有焦点时的InputMap(WHEN_IN_FOCUSED_WINDOW)(括号内表示为了得到这些InputMap 应该在getInputMap中设置的参数) 以下分别说明这三种InputMap:
组件本身拥有焦点时的InputMap:当组件拥有焦点时 键盘按键按下 则java在这个InputMap中查找键盘事件所对应的KeyStroke对象
组件的祖先拥有焦点时的InputMap:当组件的祖先拥有焦点时 键盘按键按下 则java查找这个InputMap
组件所在的窗口拥有焦点时的InputMap:当组件所在的窗口具有焦点时 键盘按键按下 则java查找这个InputMap
当一个键被按下 这个事件被转化成一个KeyStroke对象 java会查找这个Jponent的相应InputMap(例如 当组件的祖先具有焦点时 java就查找这个Jponent的祖先拥有焦点的InputMap)中是否有这个KeyStroke 如果有 取出它所对应的对象(通常是字符串) 利用这个对象在这个Jponent的ActionMap中查找 如果找到对应的行为(Action) 则java执行这个行为的actionPerformed方法(随后介绍这个方法) 从而达到处理键盘事件的目的
每一个InputMap可以具有parent属性 这个属性的值是一个InputMap 当在一个InputMap中查找不到键盘事件的KeyStroke时 java会自动在它的parent属性指定的InputMap中查找 依次向上查找 直至找到 使用parent的好处是 当有一些固定的 不希望用户进行改动的键盘映射可以存放在parent属性所指定的InputMap中 从而避免被意外修改 另外可以将多个Jponent的缺省InputMap设置具有相同的parent 使得可以共享一些键盘绑定的设置 可以通过InputMap类的setparent()方法设置它的parent属性 ActionMap也具有相同的parent属性 使用方法也相同
以上是如何将一个键盘事件对应到一个行为 以下就简单介绍行为(Action)
行为是一个实现了Action接口的类 在Action接口中定义了 个方法 其中最关键的是actionPerformed()方法 这个方法描述了这个行为的具体操作过程 其他几个方法包括setEnabled isEnabled putValue getValue addPropertyChangeListener 和removePropertyChangeListener方法 他们分别用来设置行为是否可用 判断行为可用的状态 设置和取得行为的一些属性 最后两个方法用来允许其他对象在行动对象的属性发生变化后得到通知
通常我们使用一个实现了Action接口的大部分方法的抽象类AbstractAction类作为基类 重载actionPerformed方法以实现我们的行为
我们用一个例子来具体说明如何进行实际的操作
首先编写一个具体的行为 对指定的键盘事件进行处理
public class TextAction extends AbstractAction
private String a;
public TextAction(String a)
this a = a;
public void actionPerformed(ActionEvent parm )
String b = parm getActionCommand() //得到行为的命令字符串
System out println( mand= +b)
System out println( prompt= +this a)
建立四个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 = son getInputMap()
focusFatherIm = new InputMap()
focusIm setParent(focusFatherIm)
//get WHEN_ANCESTOR_OF_FOCUSED_PONENT inputMap
ancestorIm = son getInputMap(WHEN_ANCESTOR_OF_FOCUSED_PONENT)
//get WHEN_IN_FOCUSED_WINDOW inputMap
windowIm = son getInputMap(WHEN_IN_FOCUSED_WINDOW)
在这些InputMap中分别加入键盘绑定
focusIm put(KeyStroke getKeyStroke( f ) actionFocusSon )
focusFatherIm put(KeyStroke getKeyStroke( F ) actionFocusFather )
ancestorIm put(KeyStroke getKeyStroke( a ) actionAncestor )
windowIm put(KeyStroke getKeyStroke( w ) actionWindow )
得到son组件的缺省的ActionMap 并将已经建立的行为与特定的对象(字符串)进行绑定
am = son getActionMap()
am put( actionFocusSon whenFocusSon)
am put( actionFocusFather whenFocusFather)
am put( actionAncestor ancestor)
am put( actionWindow window)
运行程序及其相应结果
单击son按钮 这时如果按下 f F a w 程序均会有相应的输出 这是因为 此时的焦点在son按钮上 而son按钮组件的三个InputMap都是有效的 所以他们对应的事件都会发生
单击parent按钮 这时按下 w 程序会有相应的输出 而按下 f F a 程序没有反应 这是因为parent按钮具有焦点 这个按钮不是son按钮的祖先 而son所在的窗口具有焦点 所以只有组件所在窗口具有焦点的InputMap是有效的
lishixinzhi/Article/program/Java/hx/201311/26304
在 java awt 或 swing 中,如何安排键盘输入到鼠标所在的位置?
【中文标题】在 java awt 或 swing 中,如何安排键盘输入到鼠标所在的位置?【英文标题】:in java awt or swing, how can I arrange for keyboard input to go wherever the mouse is? 【发布时间】:2014-07-28 19:57:43 【问题描述】:在帮助系统上工作时,我希望每个组件在鼠标悬停时提供一些帮助并且“?”键被按下。有点像工具提示,除了提供更广泛的帮助 - 本质上是一个小型网络浏览器,旨在弹出并显示文本、图像或更多内容。
我发现无论鼠标在哪里,输入总是转到同一个 KeyListener。一次只能激活一个吗?
不管怎样,这是现在可用的版本 - 感谢您的建议!
/** * 主类 JavaHelp 想要支持一个帮助功能,这样当 * 用户在组件上方输入 F1,它会创建一个弹窗解释 * 组件。 * 完整版旨在成为工具提示的老大哥,调用 * 带有可点击链接、嵌入图像等的 HTML 显示。 */ 导入 javax.swing.*; 导入 javax.swing.border.Border; 导入 java.awt.*; 导入 java.awt.event.*; 导入 java.awt.event.ActionEvent; 导入 java.awt.event.ActionListener; 导入 java.awt.event.KeyEvent; 导入 java.awt.event.KeyListener; 类 Respond2Key 扩展 AbstractAction 组件 jrp; // 合约构造器 公共 Respond2Key( 字符串文本) 超级(文本); // 确保正确完成的构造函数 public Respond2Key(字符串文本,组件 jrpIn) 超级(文本); System.out.println("用组件创建 Respond2Key" + jrpIn .toString ()); jrp = jrpIn; 公共无效setJrp(组件j) jrp = j; // 功能:对键的响应是什么 公共无效actionPerformed(ActionEvent e) // 使用 MouseInfo 获取位置,转换为窗格坐标,查找组件 点 sloc = MouseInfo.getPointerInfo().getLocation(); SwingUtilities.convertPointFromScreen(sloc, (Component) jrp); 组件 c = jrp.getComponentAt(sloc); System.out.printf("鼠标在 %5.2f,%5.2f 鼠标下的组件是 %s\n", sloc.getX(), sloc.getY(), c.toString() ); //------------------------------------------------ ---------------- // 主类 //------------------------------------------------ ---------------- 公共类 JavaHelp 扩展了 JFrame // 对象构造函数 公共 JavaHelp() // 开始构建 super("帮助系统"); this.setSize(640, 480); 容器内容 = getContentPane(); 内容.setLayout(新FlowLayout()); JButton b1 = butt("button1", 64, 48); JButton b2 = butt("button2", 96, 48); JButton b3 = butt("button3", 128, 48); JPanel p1 = 窗格(“你好”,100,100); JPanel p2 = 窗格(“世界”,200,100); 内容.add(b1); 内容.add(p1); 内容.add(b2); 内容.add(p2); 内容.add(b3); JRootPane jrp = this.getRootPane(); jrp.getInputMap(jrp.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke("F1"), "helpAction"); jrp.getActionMap().put("helpAction", 新的 Respond2Key("frame",(Component)contents) ); this.setVisible(true); this.requestFocus(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 用于实例化和监听按钮和面板的内部类。 类 ButtonListener 实现 ActionListener 私有字符串标签 = null; 公共无效 setLabel(String s) label = s; 公共无效actionPerformed(ActionEvent e) System.out.printf("处理标记为 %s 源 %s\n\n 的事件", 标签, e.getSource().toString()); // def butt( from, name, w, h) = new Jbutton (...) 受保护的 JButton 对接(字符串 s,int w,int h) JButton b = new JButton( s ); b.setSize(w, h); ButtonListener oj = new ButtonListener(); oj.setLabel(s); b.addActionListener(oj); 返回(b); // def pane = new Jpanel(...) 受保护的 JPanel 窗格(字符串名称,int w,int h) JPanel p = 新 JPanel(); p.setMinimumSize(new Dimension(w, h)); p.add(新标签(名称)); p.setBackground(颜色.黑色); p.setForeground(Color.red); 返回(p); //-------------------------------- 公共静态无效主要(字符串 [] 参数) JavaHelp jh = new JavaHelp();【问题讨论】:
【参考方案1】:输入始终转到类似的 KeyListener。
KeyEvent 会不断地发送到具有中心的部分,鼠标区域会避开关键事件的创建方式。
您应该使用 Key Bindings,而不是使用 KeyListener。在您使用键绑定时,您可以通过将限制添加到 JFrame 的根表来在生成 KeyStroke 的任何时间点召唤一个动作。仔细阅读 Swing 教学练习中关于键绑定的部分以获取更多数据。
目前在您为“?”而制作的动作中那时您可以使用 KeyStroke:
利用 MouseInfo 类获取当前鼠标区域。
利用 SwingUtilities.convertPointFromScreen(...) 切换鼠标高亮与根表比较
然后,此时,您可以使用 Container.getComponentAt(...) 来获取鼠标完成的真正片段
当您知道零件时,您可以显示您的辅助数据。
【讨论】:
【参考方案2】:我确信有更好的方法,但有一个快速而肮脏的解决方案:
private final class HoverFocusListener extends MouseInputAdapter
public void mouseEntered(MouseEvent e)
e.getComponent().requestFocusInWindow();
或者,如有必要:
public void mouseEntered(MouseEvent e)
e.getSource().setFocusable(true);
for (Component c : refToParent.getComponents()) c.setFocusable(false);
e.getComponent().requestFocusInWindow();
然后只需.addMouseListener(new HoverFocusListener())
发送给所有受影响的组件。
【讨论】:
每次我悬停时都会改变焦点吗?【参考方案3】:输入总是转到同一个 KeyListener。
一个KeyEvent总是被派发给有焦点的组件,鼠标位置与key event的产生方式无关。
您应该使用Key Bindings
,而不是使用 KeyListener。当您使用键绑定时,您可以通过将绑定添加到 JFrame 的根窗格来在生成 KeyStroke 时调用操作。阅读 Key Bindings 上的 Swing 教程部分了解更多信息。
现在在您创建的用于监听“?”的操作中然后您可以使用 KeyStroke:
-
使用
MouseInfo
类获取当前鼠标位置。
使用SwingUtilities.convertPointFromScreen(...)
将鼠标点转换为相对于根窗格
然后您可以使用Conatiner.getComponentAt(...)
来获取鼠标所在的实际组件
一旦您了解了该组件,您就可以显示您的帮助信息。
【讨论】:
以上是关于Java Swing中键盘的处理的主要内容,如果未能解决你的问题,请参考以下文章
在 java awt 或 swing 中,如何安排键盘输入到鼠标所在的位置?