Почему KeyListener работает только тогда, когда кнопка не нажата? - PullRequest
0 голосов
/ 02 июня 2018

Я хотел сделать KeyListener, чтобы остановить программу, когда я нажимаю клавишу ESC.Но это работает только тогда, когда я больше ничего не делал (нажал кнопку).Прошу прощения, если это что-то супер очевидное, но я не могу найти ошибку.

package basics;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame; 


public class Graphic extends JFrame implements ActionListener, KeyListener {

 private JButton button;

    public Graphic() {
        button = new JButton();
        button.addActionListener(this);
        button.setIcon(new ImageIcon("Image.jpg"));

        this.getContentPane().add(button);
    }
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == button){
            //some code 
        }
   } 

    public static void main(String[] args) {
        JFrame bec = new Graphic();
        bec.setDefaultCloseOperation(Graphic.EXIT_ON_CLOSE);
        bec.setSize(1731, 563);
        bec.setVisible(true);
        bec.setTitle("title");
        bec.requestFocus();
        bec.addKeyListener(new Graphic());
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_ESCAPE){
            System.exit(0);
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

} 

Ответы [ 4 ]

0 голосов
/ 02 июня 2018

Но это работает только тогда, когда я больше ничего не делал (нажал кнопку).

Нет, это не работает ( вообще ).Посмотрите на этот код:

public static void main(String[] args) {
    JFrame bec = new Graphic();
    // ..
    bec.addKeyListener(new Graphic());
}

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

Другая причина, по которой он не будет работать: потому что KeyListener (даже при добавлении к правильному экземпляру) требует, чтобы компонент, к которому он добавлен, был фокусируемым (по умолчанию JFrame нет) и имел фокус ввода (, которого у этого кадра никогда не будет, учитывая егоне фокусируется ).

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

0 голосов
/ 02 июня 2018

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

UPD: Извините, не видел, что у вас там только кнопка.

0 голосов
/ 02 июня 2018

KeyListener страдает от проблем, связанных с фокусируемостью и другими элементами управления в GUI.Простым решением будет использование API Actions .При таком подходе программа просто указывает для данного компонента «связывание» или «отображение» между любой интересующей клавишей и объектом Action (команда), который вызывается при нажатии (или отпускании) этой клавиши.Привязки клавиш связаны с определенным компонентом графического интерфейса.

В этом случае правильное решение может быть:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke; 


public class Graphic extends JFrame implements ActionListener {

private JButton button;

    public Graphic() {
        getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "Cancel"); //$NON-NLS-1$
            getRootPane().getActionMap().put("Cancel", new AbstractAction(){ //$NON-NLS-1$
                public void actionPerformed(ActionEvent e)
                {
                    dispose();
                }
            });

        button = new JButton();
        button.addActionListener(this);
        button.setIcon(new ImageIcon("Image.jpg"));

        this.getContentPane().add(button);

    }
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == button){
            //some code 
        }
   } 

    public static void main(String[] args) {
        JFrame bec = new Graphic();
        bec.setDefaultCloseOperation(Graphic.EXIT_ON_CLOSE);
        bec.setSize(1731, 563);
        bec.setVisible(true);
        bec.setTitle("title");
        bec.requestFocus();
    }

} 
0 голосов
/ 02 июня 2018

Ваша проблема - поймать KeyListener по всем компонентам.Вы можете сделать это следующим образом:

public Graphic() {
    // ...
    KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(e -> {
        if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
            dispose();
            return true;
        }
        return false;
    });
}

Когда вы добавите это, ваше приложение будет закрыто ровно после того, как вы нажмете кнопку ESC.Если вы хотите заблокировать его, например, если некоторые из ваших компонентов имеют фокус (например, JTextField, и вы хотите выполнить определенное действие), тогда вам нужно сфокусировать компонент в этом слушателе и избегать вызова dispose().

...