2014-06-28 55 views
1

我对Swing的使用并不陌生,但我对它做了大量的工作,并且正在设计一个新的应用程序。这是一个绘图应用程序。它将允许用户在空白的“查看器”窗口中的特定位置点击,使用键盘输入字母和符号,从而编辑查看器窗口某处的文本。使用KeyBindings将所有字符映射到动作

因为我没有使用JComponent来显示这个文本,所以我需要一个可靠的方式让我的应用程序接受输入。我选择了使用KeyBindings。但我的特殊查看器组件以空输入映射和空动作映射开始。

我的问题。什么是最简单的方式来映射所有的字母和符号,我可以使用我的键盘键入AbstractAction的使用ActionMap和InputMap?该动作图需要使用WHEN_IN_FOCUSED_WINDOW来捕捉接口的所有输入。

编辑: 我曾经使用的KeyListener为了做到这一点,但我没有在获得模块化的 方式,我想

我看不上的代码。彻底抛弃它。我相信这是在SSCCE:

import java.awt.event.KeyEvent; 
import static java.awt.event.KeyEvent.*; 

public class MyKeysHandler extends KeyListener { 
//blah blah blah 
//blah blah blah 
public void keyPressed(KeyEvent ke) 
{ 
// please excuse if the boolean logic of my use of masks is off 
// their proper use doesn't come to me easily 
// I hope you can get the jist 
    if((ke.getModifiersEx() & KeyEvent.SHIFT_DOWN_MASK) != 0) { 
     switch(ke.getKeyCode()) { 
      // handle capital letters 
     case VK_DELETE  : editor.handleThisSpecialKey(ke.getKeyCode); 
     case VK_BACK_SLASH : // handle back slash 
     case VK_7  : // handle the ampersand 
     case VK_8  : // handle the asterisk character 
     default   : // if just a normal letter... 
      editor.handleThisNormalKeyPlease(KeyEvent.getKeyText(ke.getKeyCode()).toUpperCase()); 
     } 
    } 
    else { 
     switch(ke.getKeyCode()) { 
     case VK_DELETE  : // handle the shift-delete command 
     case VK_BACK_SLASH : // handle the question mark 
     case VK_7  : // handle the 7 
     case VK_8  : // handle the 8 
     defualt : 
      if(ke.getKeyCode() == VK_C && ke.getModifiersEX() & KeyEvent.CTRL_DOWN_MASK) != 0) { 
       editor.handleTheCopyCommandPlease();  
      } 
      else 
       editor.handleThisKeyPlease(KeyEvent.getKeyText(ke.getKeyCode).toLowerCase()); 
     } 
    }  
} 
} 

但这真的很麻烦。每当你添加一个密钥时,你必须确保它不会与相同方法中的一些其他密钥代码发生冲突,并且对于你必须为任何应用程序制作的每一个keylistener,你都必须包含这个细致的“VK”开关代码。

我的应用程序也会有菜单,而且我也想为那些有时间的人安装新的键盘绑定或加速器(或任何他们称之为助记符?)。为了移动文本并删除它们,只需要一些特殊的组合键就可以了。至于你在上面看到的关键组合?你可以想象这对我来说有多大的噩梦。

我向你保证没有发布更多的代码,我试图遵循良好的可重用计算机编程实践模型。我有一个模型在下面运行,实际上处理编辑,以及上面运行并处理菜单按钮代码的视图。

不幸的是,我希望Java不必像上面显示的那样麻烦。键盘上的所有键除了大多数键都需要不同的响应,具体取决于您所按的键,并且KeyBindings中支持ctrl和shift之类的组合。

我的希望是有一个循环解决方案。然后,也许有一个解决方案使用WHEN-IN-ANCESTOR,也可以工作。我正在使用的输入映射是组件根窗格,但我也打算尽可能远地查看组件本身(一个JPanel)并获得其实例,但我还没有这样做,因为我'实验。

我目前访问项目的方式是这样的:这适用于我。但它不处理符号。也许如果我增加了for循环中的字符跨度?或者手动添加几个?我不知道。

import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JComponent; 
import javax.swing.JRootPane; 
import javax.swing.KeyStroke; 
public void initKeyBindingsTheEasyWay() { 

JRootPane rootPane = mainPane.getRootPane(); 
InputMap theWIMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); 
ActionMap theAMap = rootPane.getActionMap(); 
for(char c = 'A'; c <= 'Z'; c++) { 
    // lower case 
    KeyStroke little = KeyStroke.getKeyStroke("pressed " + c); 
    theWIMap.put(little, ""+Character.toLowerCase(c)); 
    theAMap.put(""+Character.toLowerCase(c), new LetterAction(Character.toLowerCase(c))); 
} 
} 

public static class LetterAction extends AbstractAction 
{ 
    char theLetter; 
    public LetterAction(char letter) 
    { 
     theLetter = letter; 
    } 

    public void actionPerformed(ActionEvent ae) 
    { 
     System.out.print(theLetter); 
    } 
} 
+0

这实际上并不是真正的关键绑定。如果你必须有一个gloabl级别的关键侦听器,你可以考虑使用AWTListener而不是 – MadProgrammer

+0

@MadProgrammer看看我上面的编辑。 – JonAar

+0

愚蠢的问题,你为什么要监视这么多键? – MadProgrammer

回答

1

我经过测试和测试,终于找到了解决办法。有兴趣的人有两种方法可以解决这个问题。我不会涉及通过搜索TextComponent的API来发现它如何在那里完成的方式。这对我来说很难实现我自己,我最终不得不走另一条路。

我采取了将字符和虚拟键映射到Actions。

这就是我正在寻找的东西:一种简单的方法来循环感兴趣的字符,从而节省代码和复杂度,简单地将击键映射到动作:如果您不关心捕获某些我已经列在下面的密钥只需从适当的数组中删除字符或虚拟键即可。你甚至可以添加新字符

首先实例化一个JComponent(我在本例中使用了一个名为mainPane的JFrame)。我想要捕获所有输入到的按键输入,因此我使用了JComponent.WHEN_IN_FOCUSED_WINDOW。

注意静态在下面的代码中导入KeyEvent常量。

import static java.awt.event.KeyEvent.*; 

mainPane.setFocusTraversalKeysEnabled(false); 
JRootPane rootPane = mainPane.getRootPane(); 
InputMap theWIMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); 
ActionMap theAMap = rootPane.getActionMap(); 

然后你就可以添加捕获字母键盘输入代码...

for(char c = 'A'; c <= 'Z'; c++) { 
    // upper case 
    KeyStroke capital = KeyStroke.getKeyStroke("typed " + c); 
    theWIMap.put(capital, Character.toString(c)); 
    theAMap.put(Character.toString(c), new KeyAction(c)); 

    // lower case 
    KeyStroke little = KeyStroke.getKeyStroke("typed " + Character.toLowerCase(c)); 
    theWIMap.put(little, Character.toString(Character.toLowerCase(c))); 
    theAMap.put(Character.toString(Character.toLowerCase(c)), new KeyAction(Character.toLowerCase(c))); 
} 

...然后编写代码来捕捉常用符号许多键盘打字(你可以看到的那些通过向下看键盘上键盘上的字体,我按照他们在Java API SE 7: Constant Field Values(?,%,〜,和|没有VK常数)中所指定的“VK常量值”顺序列出。

int[][] characters = new int[][] { 
       {'?', '%', '~', '|'}, 
       {' ', ',', '-', '.', '/'}, 
       {';', '=', '[', '\\', ']'}, 
       {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}, 
       {'*', '+', ',', '-', '.', '/', '&', '*', '\"', '<', '>', '{', '}', '`', '\''}, 
       {'@', ':', '^', '$', '!', '(', '#', '+', ')', '_'} 
       // if you're so inclined: add even more rows to the bottom 
       ,{'¡', '€', '\u02ff'} 
}; 

for(int[] range : characters) 
    for(int i = 0; i < range.length; i++) { 
     char charForKey = (char)range[i]; 
     KeyStroke keyboardKey = KeyStroke.getKeyStroke(charForKey); 
     theWIMap.put(keyboardKey, charForKey); 
     theAMap.put(charForKey, new KeyAction(charForKey)); 
    } 

...最后是代码,用于处理那些常用键盘上常见的命令键的输入。

int[][] commands = new int[][] { 
     {VK_BACK_SPACE, VK_ENTER, VK_ESCAPE}, 
     {VK_PAGE_UP, VK_PAGE_DOWN, VK_END, VK_HOME}, 
     {VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_DELETE}, 
     {VK_KP_UP, VK_KP_DOWN, VK_KP_LEFT, VK_KP_RIGHT}, 
    }; 
    for(int[] range : commands) 
     for(int i = 0; i < range.length; i++) { 
      KeyStroke keyboardKey = KeyStroke.getKeyStroke(range[i], 0); 
      String commandForKey = KeyEvent.getKeyText(range[i]).toLowerCase(); 
      theWIMap.put(keyboardKey, commandForKey); 
      theAMap.put(commandForKey, new KeyAction(commandForKey)); 
     } 

    theWIMap.put(KeyStroke.getKeyStroke("pressed " + "TAB"), "tab"); 
    theAMap.put("tab", new KeyAction("tab")); 

    theWIMap.put(KeyStroke.getKeyStroke("shift pressed " + "TAB"), "shift tab"); 
    theAMap.put("shift tab", new KeyAction("shift tab"));  

现在加上这个动作代码在这里(忽略有关编辑的部分:就是这样叫我的控制器部分):

public class KeyAction extends AbstractAction 
{ 
    private static final long serialVersionUID = 1L; 
    public char theLetter; 
    public String theCommand; 
    public enum KeyType {CHARACTER_ENTRY, KEYSTROKE_COMMAND}; 
    public final KeyType actionType; 

    public KeyAction(char letter) 
    { 
     theLetter = letter; 
     actionType = KeyType.CHARACTER_ENTRY; 
    } 

    public KeyAction(String command) 
    { 
     theCommand = command; 
     actionType = KeyType.KEYSTROKE_COMMAND; 
    } 


    public void actionPerformed(ActionEvent ae) 
    { 
     if(actionType == KeyType.CHARACTER_ENTRY) { 
      System.out.print(theLetter); 
      editor.receiveKey(theLetter); 
     } 
     else { 
      System.out.println("\n" + theCommand); 
      editor.receiveCommand(theCommand); 
     } 

    } 
} 

而且在打开应用程序的GUI窗口,你键入的东西后这个:“我喜欢马铃薯沙拉。[ENTER]现在捐$ 10.00![TAB] [SHIFT TAB]” 你应该在你的终端中看到类似的东西。

I love potato salad. 
enter 
Donate $10.00 now! 
tab 

shift tab 
1

大部分键和特殊字符出现在KeyEvent类中。至于其他字符,您可以通过将char转换为int来获取ASCII表的值。

当你在谈论需要使用WHEN_IN_FOCUSED_WINDOW的ActionMap时,在我看来你并没有使用MVC model,你应该考虑它。

+1

此解决方案不精确。什么是“大部分?”如果我循环访问这些KeyEvent.VK,如果我不知道用户的键盘外观如何过滤掉我想要的字符。 (说删除字符是通过按fn-backspace实现的组合键) – JonAar

+0

对不起,我错过了需要完整编码解决方案的部分问题。 “大多数部分”是随后排除“至于其他字符......”的任何一种方式都在文档链接中进行了精确定义。 – Typo

+0

我为无礼的粗鲁道歉。在对我的问题进行编辑时,我回答了第二部分的答案。至于第一部分,我看到在文档中,我将很多这些键盘键作为静态变量。这些变量映射到整数。理论上,迭代这些整数可能会使用InputMap.put()将每个VK映射到一个动作。 – JonAar

相关问题