首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Swing 鍵盤事件處理深度解析:InputMap/ActionMap 架構與焦點層級綁定實戰

     編輯:Java 相關知識

Swing 以 InputMap/ActionMap 取代 JDK 1.2 的 registerKeyboardAction,提供統一、靈活的鍵盤事件處理機制。本文深入解析三層焦點條件、父子映射鏈、Action 介面實作與完整範例程式。

核心架構:雙重映射表

  • InputMap:KeyStroke → Object (通常為 String 鍵值)
  • ActionMap:Object 鍵值 → Action 行為物件

流程:按鍵 → KeyStroke → 查找對應 InputMap → 取得鍵值 → 查找 ActionMap → 執行 actionPerformed。

三種焦點層級的 InputMap

每個 JComponent 擁有三個預設 InputMap,透過 getInputMap(int condition) 取得:

WHEN_FOCUSEDWHEN_ANCESTOR_OF_FOCUSED_COMPONENTWHEN_IN_FOCUSED_WINDOW
常數條件值觸發時機
0組件本身擁有焦點
1組件祖先擁有焦點
2組件所在視窗擁有焦點

單一 ActionMap 由 getActionMap() 取得,三個 InputMap 共用。

父子映射鏈

InputMap 與 ActionMap 均支援 setParent(InputMap/ActionMap):

  • 查找失敗時自動遞迴查找父映射
  • 用途:共享全域快捷鍵、保護核心綁定不被意外覆寫

Action 介面與 AbstractAction

Action 延伸 ActionListener,核心方法:

void actionPerformed(ActionEvent e)  // 必須實作:具體行為邏輯
void setEnabled(boolean b) / boolean isEnabled()  // 啟用狀態
Object getValue(String key) / void putValue(String key, Object value) // 屬性存取
void addPropertyChangeListener(PropertyChangeListener l) // 屬性變更通知

實務上繼承 AbstractAction 僅需覆寫 actionPerformed。

完整實戰範例:多層焦點綁定示範

1. 定義四種行為

class TextAction extends AbstractAction {
    private String prompt;
    TextAction(String prompt) { this.prompt = prompt; }
    public void actionPerformed(ActionEvent e) {
        System.out.println("command=" + e.getActionCommand() + ", prompt=" + prompt);
    }
}

TextAction focusSon = new TextAction("focus son");
TextAction focusFather = new TextAction("focus father");
TextAction ancestorAct = new TextAction("ancestor");
TextAction windowAct = new TextAction("window");

2. 建立元件階層:Frame → parentPanel → sonPanel → sonBtn

JPanel parentPanel = new JPanel();
JPanel sonPanel = new JPanel();
JButton sonBtn = new JButton("son");
JButton parentBtn = new JButton("parent");
parentPanel.add(sonPanel);
sonPanel.add(sonBtn);
parentPanel.add(parentBtn);
frame.add(parentPanel); // 另加入其他按鈕於 Frame 直接層級

3. 設定 sonBtn 的三層 InputMap 與父映射

InputMap focusIm = sonBtn.getInputMap(WHEN_FOCUSED);
InputMap focusFatherIm = new InputMap();
focusIm.setParent(focusFatherIm); // 保護層:防止核心綁定被覆寫

InputMap ancestorIm = sonBtn.getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
InputMap windowIm = sonBtn.getInputMap(WHEN_IN_FOCUSED_WINDOW);

4. 綁定 KeyStroke → 鍵值

focusIm.put(KeyStroke.getKeyStroke('f'), "actionFocusSon");
focusFatherIm.put(KeyStroke.getKeyStroke('F'), "actionFocusFather");
ancestorIm.put(KeyStroke.getKeyStroke('a'), "actionAncestor");
windowIm.put(KeyStroke.getKeyStroke('w'), "actionWindow");

5. 綁定鍵值 → Action

ActionMap am = sonBtn.getActionMap();
am.put("actionFocusSon", focusSon);
am.put("actionFocusFather", focusFather);
am.put("actionAncestor", ancestorAct);
am.put("actionWindow", windowAct);

執行結果驗證焦點層級邏輯

焦點位置有效按鍵說明
sonBtnf, F, a, w三層 InputMap 皆有效
parentBtnw非 sonBtn 祖先,僅視窗層級有效
Frame 上其他按鈕w同 parentBtn,僅視窗層級有效

進階技巧與最佳實踐

  1. 全域快捷鍵:在 Root Pane 的 WHEN_IN_FOCUSED_WINDOW InputMap 設定,整個視窗生效
  2. 條件式啟用:Action.setEnabled(false) 可動態禁用快捷鍵,無需移除綁定
  3. 避免衝突:子組件 InputMap 優先級高於祖先,善用父映射鏈管理優先級
  4. KeyStroke 靈活表示:getKeyStroke("ctrl shift X")、getKeyStroke(KeyEvent.VK_F1, 0) 等多種建構方式

掌握 InputMap/ActionMap 架構,即可構建清晰、可維護、符合平台慣例的鍵盤交互體驗。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved