簡體   English   中英

Java KeyAdapter 與 Swing 鍵綁定?

[英]Java KeyAdapter vs. Swing Key Bindings?

我有一個 java swing 程序,我之前使用KeyAdapter class 進行控制。 出於幾個原因,我決定改用 swing 的內置鍵綁定系統(使用InputMapActionMap )。 在切換時,我遇到了一些令人困惑的行為。

為了測試這些系統,我有一個簡單的 JPanel:

public class Board extends JPanel {

    private final int WIDTH = 500;
    private final int HEIGHT = 500;
    
    private boolean eventTest = false;

    public Board() {
        initBoard();
        initKeyBindings();
    }

    // initialization
    // -----------------------------------------------------------------------------------------
    private void initBoard() {
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setFocusable(true);
    }

    private void initKeyBindings() {

        getInputMap().put((KeyStroke.getKeyStroke(KeyEvent.VK_SHIFT, 0), "Shift Pressed");

        getActionMap().put("Shift Pressed", new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                eventTest = true;
            }
        });

    }

    // drawing
    // -----------------------------------------------------------------------------------------
    @Override
    protected void paintComponent(Graphics g) {
        // paint background
        super.paintComponent(g);

        g.setColor(Color.black);
        g.drawString("Test: " + eventTest, 10, 10);
        eventTest = false;
    }

同樣在我的程序中,我有一個循環調用repaint()方法每秒 10 次,以便我可以看到 eventTest 得到更新。 我希望該系統在按下 shift 鍵的幀eventTest顯示為 true,否則為 false。 我還通過更改相關鍵碼測試了其他鍵。

當我想測試 KeyAdapter 時,我將這個塊添加到initBoard()方法中,並在構造函數中注釋掉initKeyBindings()

this.addKeyListener(new KeyAdapter() {
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
            eventTest = true;
        }
    }
});

使用KeyAdapter class 時,它按預期工作。 但是,當我切換到使用鍵綁定時,它變得令人困惑。 出於某種原因, eventTest僅在我按下兩個 shift 鍵時才顯示為 true。 如果我按住任一 shift 鍵,當我按下另一個時,事件測試在框架上變為 true,然后返回 false。 我希望它在按下一個 shift 鍵時執行此操作,而不必按住另一個。

此外,當我將其設置為在右箭頭按下時觸發時,會發生稍微不同的行為。 KeyAdapter和鍵綁定模式中,發生的情況是 eventTest 在我按下右箭頭的幀上變為真,然后在短時間內返回假,然后只要我按住箭頭就變為真。 從在線閱讀文檔來看,這似乎是由依賴於操作系統的行為(我正在運行 Ubuntu 18.04)在按住鍵時繼續發送KeyPressed事件引起的。 我感到困惑的是,為什么 shift 鍵的這種行為與右箭頭的行為不同。 如果可能的話,我想找到一種方法使eventTest僅在按下鍵的第一幀上為真。

關於造成這種情況的任何想法? 謝謝!

我至少找到了部分答案。

對於在使用鍵綁定時我必須同時按住兩個 shift 鍵來生成按鍵事件的問題,有一個簡單的修復方法。 所需要做的就是將添加到InputMap的內容從:

getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SHIFT, 0), "pressed");

getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SHIFT, KeyEvent.SHIFT_DOWN_MASK), "pressed");

我不完全確定為什么輸入 map 將按下單個 shift 鍵視為KeyEvent ,鍵碼為VK_SHIFTSHIFT_DOWN_MASK ,但這似乎就是它正在做的事情。 如果僅在已經按下一個 shift 鍵並且用戶嘗試按下另一個 shift 鍵的情況下應用掩碼,這對我來說會更直觀,但有趣的是,如果按住一個 shift 鍵並且此綁定不再檢測事件並且另一個被按下。 詭異的。

其他鍵的問題有稍微不太干凈的解決方案。 至於為什么 shift 的行為與其他鍵不同的問題。 我相信這是操作系統內置的有意設計。 例如,如果用戶按住右箭頭(或許多其他鍵,例如每個文本字符鍵),則可以合理地假設他們想要重復與該鍵相關的操作。 即,如果用戶正在打字,並且按住“a”,他們可能想要快速連續地將多個“a”字符輸入到文本文檔中。 但是,以類似方式自動重復 shift 鍵(在大多數情況下)對用戶沒有用處。 因此,沒有為 shift 鍵生成重復事件是有道理的。 我沒有任何來源支持這一點,這只是一個假設,但對我來說很有意義。

為了消除這些額外的事件,似乎沒有一個好的解決方案。 一件有效但草率的事情是存儲當前按下的所有鍵的列表,然后讓您的操作 map 在執行其操作之前檢查該鍵是否被按下。 另一種方法是使用計時器並忽略發生的事件以彼此及時關閉(有關更多詳細信息,請參閱這篇文章)。 這兩種實現都需要更多的 memory 使用和您希望跟蹤的每個鍵的代碼,因此它們並不理想。

使用KeyAdapter而不是 Key Bindings 可以實現稍微更好的解決方案 (IMO)。 該解決方案的關鍵在於按住一個鍵的同時按下一個鍵會中斷自動重復事件的stream,並且不會再次恢復原鍵(即使釋放第二個鍵)。 正因為如此,我們實際上只需要跟蹤最后一次按下的鍵,以便准確過濾掉所有自動重復事件,因為這是唯一可以發送這些事件的鍵。

代碼看起來像這樣:

addKeyListener(new KeyAdapter() {
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        
        if (keyCode != lastKeyPressed && keyCode != KeyEvent.VK_UNDEFINED) {
            // do some action
            lastKeyPressed = keyCode;
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // do some action
        lastKeyPressed = -1; // indicates that it is not possible for any key 
                             // to send auto-repeat events currently
    }
});

這種解決方案當然會失去 Swing 的鍵綁定系統提供的一些靈活性,但它有一個更簡單的解決方法。 您可以創建自己的 map 的intAction (或者實際上任何其他方便描述您想要做什么的類型),而不是向InputMapActionMap添加鍵綁定,而是將它們放在那里。 接下來,不要將您想要執行的操作的直接代碼放在KeyAdapter中,而是放置類似myMap.get(e.getKeyCode()).actionPerformed();的內容。 . 這允許您通過在 map 上執行相應的操作來添加、刪除和更改鍵綁定。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM