KeyListener перестает работать после нажатия на холст - PullRequest
0 голосов
/ 15 февраля 2020

У меня просто KeyHandler

public class KeyHandler implements KeyListener {
    private final Set<Integer> keyEvents = new LinkedHashSet<>();
    public Set<Integer> pressedKeys() {
        return keyEvents;
    }

    @Override
    public void keyPressed(KeyEvent e) {
        keyEvents.add(e.getKeyCode());
    }

    @Override
    public void keyReleased(KeyEvent e) {
        keyEvents.remove(e.getKeyCode());
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }
}

Что добавлено к JFrame
frame.addKeyListener(keyListener);

Покой, вероятно, не имеет значения, но я прохожу экземпляр KeyBinder

public class KeyBinder {
    private final Map<Integer, GameEvent> bindings = new HashMap<>();
    private final KeyHandler keyHandler;

    public KeyBinder(KeyHandler keyHandler) {
        this.keyHandler = keyHandler;
        bindings.put(KeyEvent.VK_A, MoveEvent.MOVE_LEFT);
        bindings.put(KeyEvent.VK_D, MoveEvent.MOVE_RIGHT);
        bindings.put(KeyEvent.VK_S, MoveEvent.MOVE_DOWN);
        bindings.put(KeyEvent.VK_W, MoveEvent.MOVE_UP);
    }

    public List<GameEvent> mapEvents() {
        final var events = new ArrayList<GameEvent>();
        keyHandler.pressedKeys().forEach(key -> events.add(bindings.get(key)));
        return events;
    }
}

А затем я передаю эти GameEvents в Player экземпляр, чтобы заставить его двигаться

@Override
public void update(java.util.List<GameEvent> events) {
    events.forEach(this::handleEvent);
}

private void handleEvent(GameEvent event) {
    if (event instanceof MoveEvent) {
        updatePosition((MoveEvent) event);
    }
}

private void updatePosition(MoveEvent event) {
    switch (event) {
        case MOVE_UP -> position = new Position(position.getX(), position.getY() - speed);
        case MOVE_DOWN -> position = new Position(position.getX(), position.getY() + speed);
        case MOVE_RIGHT -> position = new Position(position.getX() + speed, position.getY());
        case MOVE_LEFT -> position = new Position(position.getX() - speed, position.getY());
    }
}

Это прекрасно работает, если я ' Я запускаю один экземпляр моего приложения. Но поскольку это будет онлайн-игра, я хочу запустить 2 экземпляра одновременно для тестирования. К сожалению, когда я запускаю второй экземпляр, мой KeyHandler больше не работает ни в одном из них, он просто не записывает KeyEvents. Я знаю, что мое приложение все еще работает, потому что мое серверное приложение продолжает получать данные от обоих клиентов.

Редактировать:

Я только что понял, что что-то еще является проблемой. KeyHandler перестает работать, когда я нажимаю холст ... Мне даже не нужен второй экземпляр моего приложения. Вот код JFrame и Canvas, который я использую для рисования вещей ...

 public class Display {
        private JFrame frame;
        private Canvas canvas;

        public Display(KeyListener keyListener) {
            initFrame(keyListener);
            initCanvas();
            frame.add(canvas);
            frame.pack();
        }

        private void initFrame(KeyListener keyListener) {
            frame = new JFrame(GameConfig.TITLE);
            frame.setSize(GameConfig.SCREEN_WIDTH, GameConfig.SCREEN_HEIGHT);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setResizable(false);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
            frame.addKeyListener(keyListener);
        }

        private void initCanvas() {
            canvas = new Canvas();
            canvas.setPreferredSize(new Dimension(GameConfig.SCREEN_WIDTH, GameConfig.SCREEN_HEIGHT));
            canvas.setMaximumSize(new Dimension(GameConfig.SCREEN_WIDTH, GameConfig.SCREEN_HEIGHT));
            canvas.setMinimumSize(new Dimension(GameConfig.SCREEN_WIDTH, GameConfig.SCREEN_HEIGHT));
        }

        public Canvas getCanvas() {
            return canvas;
        }
    }

1 Ответ

2 голосов
/ 15 февраля 2020

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

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

Добавить FocusListener к кадру.

    frame.addFocusListener(new FocusListener() {
            public void focusGained(FocusEvent e) {}
            public void focusLost(FocusEvent e) {frame.requestFocus();}
    });

Отключить фокусируемость холста .

    canvas.setFocusable(false);

Эти решения не рекомендуются, но для вашего случая это подойдет.

...