Привязки Java Swing Key - отсутствует действие для выпущенного ключа - PullRequest
10 голосов
/ 15 декабря 2011

Зарегистрировав привязки клавиш для «ПРОБЕЛ» и «освобожденный ПРОБЕЛ», которые работают так, как объявлено, когда пробел является единственной клавишей, нажатой / отпущенной, я замечаю, что нажатие пробела, затем нажатие ctrl (или любой другой клавиши-модификатора), затем освобождение пробелаи, наконец, отпускание Ctrl вызовет действие, связанное с «ПРОБЕЛ», но не действие, связанное с «освобожденный ПРОБЕЛ».

Каков предпочтительный способ заставить действие выполняться, когда пробел больше не нажимается (или одновременно нажимается клавиша-модификатор)?Я пробовал это только в 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);
      }
    });
  }
}

ОБНОВЛЕНИЕ : Это способ избежать залипания пробела при случайном нажатии 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 ]

7 голосов
/ 16 декабря 2011

Имеет смысл, что событие released SPACE не запускается, когда клавиша управления все еще удерживается нажатой.Я ожидаю, что событие control released SPACE будет запущено.

Добавьте следующее в ваш код:

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

По той же причине событие SPACE не сработает, если вы сначалаудерживайте нажатой клавишу управления.Поэтому вам также необходимо добавить привязки для control SPACE.

Это необходимо сделать для всех клавиш-модификаторов, что может быть или не быть более простым решением, чем отслеживание событий клавиш.

4 голосов
/ 15 декабря 2011

Возможно, ваша ОС не запускает события keyReleased, а только события keyPressed и keyTyped или какую-либо другую комбинацию, поэтому сначала проверьте это.Возможно, вам просто нужно проверить наличие keyTyped событий вместо keyReleased, и вы с этим покончите.

Краткий ответ:

Используйте bitmask или массив для отслеживания того, какие клавиши в данный момент находятся в «нажатом» состоянии, а затем используйте их для запуска событий.То есть не используйте события Swing напрямую для запуска ответов в вашем приложении - вам нужен дополнительный слой, который по существу хранит состояние клавиатуры, и из этого состояния выполняет соответствующие действия.

Естьтакже доступны методы ( см. в конце этого учебника - «isAltDown», «isCtrlDown» и т. д. ), чтобы проверить, нажимаются ли клавиши-модификаторы при получении события, такого как нажатие клавиши «Пробел».

Длинный ответ:

Вы правы, что события запускаются при нажатии и отпускании клавиш.Это должно работать таким образом, чтобы вы могли поддерживать приложения, которые должны обрабатывать эти события отдельно, а не вместе.Одним из примеров (хотя и не единственным) являются видеоигры на ПК, где вы можете одновременно нажимать несколько букв / клавиш-модификаторов (например, A для перехода влево и W для перехода вперед) иигра должна рассматривать эти два события как отдельные входы, а не как композитные входы, в результате чего ваше движение будет идти вперед-влево.

Итак, что вы в основном хотите сделать, если вам нужно иметь дело с композитными входами,Это простой массив действий, на которые должно реагировать ваше приложение, и связанные с ними привязки клавиш (неважно, однозначные или многоключевые).Когда клавиша нажата, вы в основном включаете флаг для этой клавиши, который говорит, что она в данный момент «нажата», и очищаете флаг, когда она отпущена.

Затем, чтобы вызвать события, вы просто проверяете все клавиши, которыенажимаются (путем проверки, какие клавиши «флажки» активны), и если нажата комбинация клавиш определенного события, событие запускается.

Если у вас менее 32 клавиш, которые запускают события, то вы можетена самом деле это делается с битовой маской и 32-битным int значением, а не массивом.На самом деле, сделать это намного проще, если вы можете.Если вам нужно до 64 ключей, сделайте то же самое с long.Если у вас очень мало клавиш, запускающих события (например, 8 или меньше), вы можете использовать 8-битный тип short.

...