java swing鍵綁定 - 釋放鍵的缺失操作

[英]java swing key bindings - missing action for released key


Having registered key bindings for "SPACE" and "released SPACE" which works as advertised when space is the only key pressed/released, I notice that pressing space, then pressing ctrl (or any other modifier key), then releasing space and finally releasing ctrl will cause the action associated with "SPACE" to be performed, but not the action associated with "released SPACE".

注冊了“SPACE”和“已發布的SPACE”的鍵綁定,當空間是唯一按下/釋放的鍵時,按照廣告的方式工作,我注意到按下空格,然后按ctrl(或任何其他修改鍵),然后釋放空間,最后釋放ctrl將導致執行與“SPACE”關聯的操作,但不會執行與“已釋放的SPACE”關聯的操作。

What is the preferred way to cause the action to be performed once space is no longer pressed (or a modifier key is pressed simultaneously)? I only tried this on Windows 7, 64-bit.

一旦不再按空格(或同時按下修改鍵),導致動作執行的首選方法是什么?我只在Windows 7,64位上嘗試過這個。

import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import java.awt.event.ActionEvent;
import java.awt.Cursor;

class Bind extends JPanel {
  {
    getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "pressed");
    getInputMap().put(KeyStroke.getKeyStroke("released SPACE"), "released");
    getActionMap().put("pressed", new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        System.out.println("pressed");
        setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 
      }
    });
    getActionMap().put("released", new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        System.out.println("released");
        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
      }
    });
  }
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override public void run() {
        JFrame f = new JFrame("Key Bindings");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        f.add(new Bind());
        f.setSize(640, 480);
        f.setVisible(true);
      }
    });
  }
}

UPDATE: This is the way to avoid sticky space when accidentally hitting ctrl, alt, or shift before releasing space:

更新:這是在釋放空間之前意外點擊ctrl,alt或shift時避免粘滯空間的方法:

import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
import java.awt.event.ActionEvent;
import java.awt.Cursor;

class Bind extends JPanel {
  {
    getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "pressed");
    getInputMap().put(KeyStroke.getKeyStroke("released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("ctrl released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("shift released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("shift ctrl released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("alt released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("alt ctrl released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("alt shift released SPACE"), "released");
    getInputMap().put(KeyStroke.getKeyStroke("alt shift ctrl released SPACE"), "released");
    getActionMap().put("pressed", new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        System.out.println("pressed");
        setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 
      }
    });
    getActionMap().put("released", new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        System.out.println("released");
        setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
      }
    });
  }
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override public void run() {
        JFrame f = new JFrame("Key Bindings");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        f.add(new Bind());
        f.setSize(640, 480);
        f.setVisible(true);
      }
    });
  }
}

2 个解决方案

#1


6  

Makes sense that the released SPACE event isn't fired when the Control key is still held down. I would expect a control released SPACE event to be fired.

有意義的是,當仍然按住Control鍵時,不會觸發釋放的SPACE事件。我希望控制釋放SPACE事件被解雇。

Add the following to your code:

將以下內容添加到您的代碼中:

getInputMap().put(KeyStroke.getKeyStroke("control released SPACE"), "released");

For the same reason the SPACE event won't fire if you first hold the Control key down. So you would also need to add bindings for control SPACE.

出於同樣的原因,如果您先按住Control鍵,SPACE事件將不會觸發。所以你還需要為控制SPACE添加綁定。

You would need to do this for all the modifier keys, which may or may not be a simpler solution than tracking the key events.

您需要對所有修改鍵執行此操作,這可能是也可能不是跟蹤關鍵事件的簡單解決方案。

#2


3  

It's possible that your OS doesn't fire keyReleased events, but only keyPressed and keyTyped events, or some other combination, so check for that first. You might just need to check for keyTyped events instead of keyReleased and you'll be done with it.

您的操作系統可能無法觸發keyReleased事件,但只觸發keyPressed和keyTyped事件或其他組合,因此請先檢查該事件。您可能只需要檢查keyTyped事件而不是keyReleased,您將完成它。

Short answer:

簡短回答:

Use a bitmask or an array to keep track of which keys are currently in the "pressed" state, then use those valued to trigger events. That is, don't use the Swing events directly to trigger responses in your application - you need an extra layer that essentially stores the state of the keyboard, and from that state, takes the relevant actions.

使用位掩碼或數組來跟蹤當前處於“已按下”狀態的鍵,然后使用那些值來觸發事件。也就是說,不要直接使用Swing事件來觸發應用程序中的響應 - 您需要一個基本上存儲鍵盤狀態的額外層,並從該狀態開始執行相關操作。

There are also methods available (see the end of this tutorial - "isAltDown", "isCtrlDown" etc.) to check if modifier keys are pressed when you receive an event like the "Space" key being pressed.

還有一些方法可用(參見本教程結尾 - “isAltDown”,“isCtrlDown”等),以檢查當您收到按下“Space”鍵之類的事件時是否按下了修改鍵。

Long answer:

答案很長:

You're correct that the events get fired when the keys get pressed and released. It kind of has to work that way so that you can support applications that should treat those events separately, as opposed to together. One example (though this isn't the only one) is video games on PC where you might be pressing multiple letter/modifier keys at once (for example, A to go left, and W to go forward) and the game has to treat these two event as distinct inputs, as opposed to composite inputs, resulting in your movement going forward-left.

你按下並釋放按鍵時會觸發事件,這是正確的。它必須以這種方式工作,以便您可以支持應該單獨處理這些事件的應用程序,而不是一起處理。一個例子(雖然這不是唯一的例子)是PC上的視頻游戲,你可能會同時按下多個字母/修改鍵(例如,A向左移動,W向前移動)游戲必須對待這兩個事件作為不同的輸入,而不是復合輸入,導致你的前進 - 左移動。

So, what you basically want to do, if you need to deal with composite inputs, is have a simply array of the actions your app needs to respond to, and their associated key bindings (whether single or multi-keys doesn't really matter). When a key is pressed, you basically turn on a flag for that key that says it's currently "pressed", and clear the flag when it's released.

所以,你基本上想做的事情,如果你需要處理復合輸入,就有一個簡單的應用程序需要響應的動作數組,以及它們相關的鍵綁定(無論是單鍵還是多鍵都不重要) )。當按下某個鍵時,你基本上會打開該鍵的標志,表示它當前處於“按下”狀態,並在釋放時清除該標志。

Then, to trigger your events, you just check all keys that are pressed (via checking which key "flags" are active), and if a particular event's key combination is pressed, then the event is fired.

然后,要觸發您的事件,您只需檢查所有按下的鍵(通過檢查哪些鍵“標志”處於活動狀態),如果按下特定事件的鍵組合,則觸發事件。

If you have fewer than 32 keys that trigger events, then you can actually do this with a bitmask and a 32-bit int value, rather than an array. In fact, it's much simpler to do it this way if you can. If you need up to 64 keys, do the same thing with a long. If you have very few keys that trigger events (8 or less, for example) you can use the 8-bit short type.

如果你有少於32個觸發事件的鍵,那么你實際上可以使用位掩碼和32位int值,而不是數組。事實上,如果可以的話,這樣做會簡單得多。如果您需要最多64個密鑰,請執行相同的操作。如果您觸發事件的鍵很少(例如8或更少),則可以使用8位短類型。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2011/12/15/725fe446a9f79622d9c5a17615a74768.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com