2014-06-28 50 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

相關問題