Пропуск Java KeyEvents - PullRequest
       9

Пропуск Java KeyEvents

2 голосов
/ 04 января 2011

У меня есть программа, в которой пользователь может нажать клавишу для выполнения действия. Это одно событие занимает немного времени. Пользователь также может удерживать эту клавишу и выполнять действие много раз подряд. Проблема в том, что события keyPress () ставятся в очередь быстрее, чем события могут быть обработаны. Это означает, что после того, как пользователь отпускает ключ, обрабатываются события, которые были поставлены в очередь от пользователя, ранее удерживавшего клавишу. Я также заметил, что событие keyRelease не происходит до тех пор, пока не будет обработано окончательное событие keyPress, независимо от того, когда ключ был фактически выпущен. Я хотел бы иметь возможность либо 1. Определите событие отпускания ключа и игнорируйте будущие события keyPress, пока пользователь фактически не нажмет клавишу еще раз. 2. Не выполняйте последующее событие keyPress до тех пор, пока не завершится первый, а затем определите, когда клавиша не нажата, и просто остановите.

Кто-нибудь знает, как это сделать?

Ответы [ 3 ]

2 голосов
/ 04 января 2011

Отказ от ответственности : Я плохо себя чувствую, поэтому этот код ужасен, как будто ... он тоже болен.

Что я хочу, чтобы произошло : Чтобы получить доступ к DirectInput для получения состояния клавиатуры, а не событий. Это далеко за рамки этого вопроса, хотя. Таким образом, мы будем поддерживать наше собственное состояние действия.

Проблема в том, что вы выполняете свое действие в потоке пользовательского интерфейса. Вам нужно порождать рабочий поток и игнорировать последующие события, пока ваше действие не будет завершено.

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

Существует также еще одна метка, которая показывает, сколько действий было выполнено до сих пор.

Создание нового действия

Важная часть заключается в том, чтобы все события ключа пользовательского интерфейса происходили, а не блокировались в потоке пользовательского интерфейса, заставляя их стоять в очереди.

public void keyPressed(KeyEvent e) {
    char keyChar = e.getKeyChar();
    System.out.println("KeyChar: " + keyChar);
    // Press a to start an Action
    if (keyChar == 'a') {
        if (!mAction.isRunning()) {
            mTotalActions.setText("Ran " + (++mTotalActionsRan) + " actions.");
            System.out.println("Starting new Action");
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    mAction.run();
                }
            });
            thread.start();
        }
    }
}

Обновления в потоке пользовательского интерфейса

Если ваше действие выполняет какие-либо обновления пользовательского интерфейса, необходимо использовать метод SwingUtilities.invokeLater. Этот метод поставит ваш код в очередь для запуска в потоке пользовательского интерфейса. Вы не можете изменить пользовательский интерфейс в потоке, отличном от потока пользовательского интерфейса. Кроме того, используйте только SwingUtilities для обновления компонентов пользовательского интерфейса. Любые вычисления, обработка и т. Д., Которые не вызывают методы для Компонента, могут выполняться вне области SwingUtilities.invokeLater.

Полный список кодов

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package stackoverflow_4589538;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class Main extends JFrame {

    private JLabel mActionLabel;
    private JLabel mTotalActions;
    private int mTotalActionsRan;

    private class MyAction {

        private boolean mIsRunning = false;

        public void run() {
            // Make up a random wait cycle time
            final int cycles = new Random().nextInt(100);
            for (int i = 0; i < cycles; ++i) {
                final int currentCycle = i;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                }
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                            mActionLabel.setText("Cycle " + currentCycle + " of " + cycles);
                    }
                });
            }
            completed();
        }

        public synchronized void start() {
            mIsRunning = true;
        }

        public synchronized void completed() {
            mIsRunning = false;
        }

        public synchronized boolean isRunning() {
            return mIsRunning;
    }
}
    private MyAction mAction = new MyAction();

    public Main() {
        setLayout(null);
        setBounds(40, 40, 800, 600);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                char keyChar = e.getKeyChar();
                System.out.println("KeyChar: " + keyChar);
                // Press A to start an Action
                if (keyChar == 'a') {
                if (!mAction.isRunning()) {
                        mTotalActions.setText("Ran " + (++mTotalActionsRan) + " actions.");
                        System.out.println("Starting new Action");
                        Thread thread = new Thread(new Runnable() {

                            public void run() {
                                mAction.run();
                            }
                        });
                        // I had this within the run() method before
                        // but realized that it is possible for another UI event
                        // to occur and spawn another Action before, start() had
                        // occured within the thread
                        mAction.start();
                        thread.start();
                    }
                }
            }

        @Override
            public void keyReleased(KeyEvent e) {
            }
        });

        mActionLabel = new JLabel();
        mActionLabel.setBounds(10, 10, 150, 40);

        mTotalActions = new JLabel();
        mTotalActions.setBounds(10, 50, 150, 40);

        add(mActionLabel);
        add(mTotalActions);
    }    

    public static void main(String[] args) {
        new Main().setVisible(true);
    }
}
1 голос
/ 04 января 2011

Я также заметил, что событие keyRelease не происходит до тех пор, пока не будет обработано окончательное событие keyPress, независимо от того, когда ключ был фактически выпущен

Это зависит от используемой вами ОС. Это поведение в Windows (что имеет смысл для меня). На Unix или Mac я полагаю, что вы получаете несколько событий keyPressed, keyReleased. Таким образом, ваше решение не должно основываться на событиях keyReleased.

У меня есть программа, в которой пользователь может нажать клавишу для выполнения действия.

Тогда вам следует использовать связывание клавиш, а не KeyListener. Прочитайте раздел из учебника по Swing на Как использовать привязки клавиш для получения дополнительной информации.

Когда вызывается действие, вы можете отключить его. Я не уверен, помешает ли это снова запустить KeyStroke, или вам все равно нужно будет проверить состояние активации действия. Затем, когда код действия завершится, вы можете снова включить действие.

Кроме того, этот долго работающий код не должен выполняться в EDT. Прочитайте раздел учебника Swing по параллелизму для получения дополнительной информации об этом и о решениях.

0 голосов
/ 04 января 2011

Вам нужно будет перейти к варианту 1. Как только вы начнете более длительный процесс, установите некоторое логическое значение на некоторое время, чтобы указать, что вы работаете над ним, и выбросьте другие входящие идентичные запросы. После завершения процесса установите логическое значение и разрешите дополнительные события.

...