JFrame 용 응답하지 않는 KeyListener


80

나는를 구현하기 위해 노력하고있어 KeyListener내을 위해 JFrame. 생성자에서 다음 코드를 사용하고 있습니다.

System.out.println("test");
addKeyListener(new KeyListener() {
    public void keyPressed(KeyEvent e) { System.out.println( "tester"); }

    public void keyReleased(KeyEvent e) { System.out.println("2test2"); }

    public void keyTyped(KeyEvent e) { System.out.println("3test3"); }
});

실행하면 test콘솔에 메시지가 나타납니다. 그러나 키를 누르면 마치 KeyListener거기에없는 것처럼 다른 메시지 가 표시되지 않습니다.

나는 초점이에 없기 때문에이 될 수 있다고 생각 JFrame
하고 그들이 있도록 KeyListener이벤트를 수신하지 않습니다. 그러나 나는 그것이 확실합니다.

내가 놓친 것이 있습니까?

답변:


51

필요한 모든 구성 요소에 keyListener를 추가해야합니다. 포커스가있는 구성 요소 만 이러한 이벤트를 보냅니다. 예를 들어 JFrame에 TextBox가 하나만있는 경우 해당 TextBox에 포커스가 있습니다. 따라서이 구성 요소에도 KeyListener를 추가해야합니다.

과정은 동일합니다.

myComponent.addKeyListener(new KeyListener ...);

참고 : 일부 구성 요소는 JLabel과 같이 초점을 맞출 수 없습니다.

초점을 맞출 수 있도록 설정하려면 다음을 수행해야합니다.

myComponent.setFocusable(true);

2
네 말이 맞았습니다. 프로그램이 시작될 때 초점이 버튼 A에 있음을 약간 알 수 있습니다. 각 버튼에 키 리스너를 추가하면이 문제가 해결되었습니다. 그것은 조금 이상합니다. JFrame에 키 리스너를 추가하면 작동한다고 생각하지만 그렇지 않습니다. 감사!
Tomek

키보드에서 수신하는 JFrame에 리스너를 만들었습니다. 창이 앞에 있지 않아도 패시브 모드로 작동하고 싶습니다. JFrame은 수동 모드에서 수신 대기하지 않습니다.
우스만

133

당신은 모든 구성 요소에 리스너를 등록하지 않으려면,
당신은 할 수 자신을 추가KeyEventDispatcher 받는 사람 KeyboardFocusManager:

public class MyFrame extends JFrame {    
    private class MyDispatcher implements KeyEventDispatcher {
        @Override
        public boolean dispatchKeyEvent(KeyEvent e) {
            if (e.getID() == KeyEvent.KEY_PRESSED) {
                System.out.println("tester");
            } else if (e.getID() == KeyEvent.KEY_RELEASED) {
                System.out.println("2test2");
            } else if (e.getID() == KeyEvent.KEY_TYPED) {
                System.out.println("3test3");
            }
            return false;
        }
    }
    public MyFrame() {
        add(new JTextField());
        System.out.println("test");
        KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        manager.addKeyEventDispatcher(new MyDispatcher());
    }

    public static void main(String[] args) {
        MyFrame f = new MyFrame();
        f.pack();
        f.setVisible(true);
    }
}

5
KeyboardFocusManager는 응용 프로그램 전체입니다. 여러 프레임이 있으면 문제가 발생합니까?
neoedmund

2
그래서 이것은 다음과 같이 작동합니다 : foreach ( "focusable components in the frame"as _) {_.addkeylistener (frameKeylistener);}
neoedmund

16

InputMaps 및 ActionMaps는 구성 요소, 구성 요소 및 모든 하위 구성 요소 또는 전체 창에 대한 주요 이벤트를 캡처하도록 설계되었습니다. 이것은 JComponent.getInputMap ()의 매개 변수를 통해 제어됩니다. 문서는 키 바인딩 사용 방법을 참조하십시오 .

이 디자인의 장점은 모니터링에 중요한 키 입력을 선택하고 해당 키 입력에 따라 다른 작업을 실행할 수 있다는 것입니다.

이 코드는 이스케이프 키가 창의 아무 곳에서나 치면 JFrame에서 dispose ()를 호출합니다. JFrame은 JComponent에서 파생되지 않으므로 JFrame에서 다른 구성 요소를 사용하여 키 바인딩을 만들어야합니다. 컨텐츠 창은 이러한 구성 요소 일 수 있습니다.

InputMap inputMap; 
ActionMap actionMap;
AbstractAction action;
JComponent component;

inputMap  = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
actionMap = component.getActionMap();

action    = new AbstractAction()
{
   @Override
   public void actionPerformed(ActionEvent e)
   {
      dispose();
   }
};

inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "dispose");
actionMap.put("dispose", action);

10

KeyListener낮은 수준이며 단일 구성 요소에만 적용됩니다. 더 유용하게 만들려는 시도에도 불구하고 많은 JFrame구성 요소 구성 요소가 생성되지만 가장 분명한 것은 콘텐츠 창입니다. JComboBoxUI도 유사한 방식으로 구현되는 경우가 많습니다.

마우스 이벤트가 키 이벤트와 약간 다른 이상한 방식으로 작동한다는 점은 주목할 가치가 있습니다.

수행해야 할 작업에 대한 자세한 내용은 Application wide keyboard shortcut-Java Swing 에 대한 내 답변을 참조하십시오 .


10

JFrame이 이미 리스너를 추가 한 FOCUS에 대한 실제 문제라는 것을 읽을 때까지 동일한 문제가 발생했지만 JFrame 내에 초점을 맞출 수있는 구성 요소가 많기 때문에 투어 프레임이 초점에 있지 않습니다.

JFrame.setFocusable(true);

행운을 빕니다


2
나는 이것이 내가 더 이상 응답 다음 내 JFrame의에 모든 KeyListener 뭔가를 사용하는 경우에만 때까지 작동하는 것을 발견
user3328784

9

Deion (및 유사한 질문을하는 다른 사람)은 위의 Peter의 코드를 사용할 수 있지만 표준 출력으로 인쇄하는 대신 키 코드 PRESSED, RELEASED 또는 TYPED를 테스트합니다.

@Override
public boolean dispatchKeyEvent(KeyEvent e) {
    if (e.getID() == KeyEvent.KEY_PRESSED) {
        if (e.getKeyCode() == KeyEvent.VK_F4) {
            dispose();
        }
    } else if (e.getID() == KeyEvent.KEY_RELEASED) {
        if (e.getKeyCode() == KeyEvent.VK_F4) {
            dispose();
        }
    } else if (e.getID() == KeyEvent.KEY_TYPED) {
        if (e.getKeyCode() == KeyEvent.VK_F4) {
            dispose();
        }
    }
    return false;
}

4

JFrame 의 모든 텍스트 필드의 주요 이벤트를 캡처하기 위해 주요 이벤트 포스트 프로세서를 사용할 수 있습니다. 다음은 명백한 포함을 추가 한 후 작동하는 예입니다.

public class KeyListenerF1Demo extends JFrame implements KeyEventPostProcessor {
    public static final long serialVersionUID = 1L;

    public KeyListenerF1Demo() {
        setTitle(getClass().getName());

        // Define two labels and two text fields all in a row.
        setLayout(new FlowLayout());

        JLabel label1 = new JLabel("Text1");
        label1.setName("Label1");
        add(label1);

        JTextField text1 = new JTextField(10);
        text1.setName("Text1");
        add(text1);

        JLabel label2 = new JLabel("Text2");
        label2.setName("Label2");
        add(label2);

        JTextField text2 = new JTextField(10);
        text2.setName("Text2");
        add(text2);

        // Register a key event post processor.
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
                .addKeyEventPostProcessor(this);
    }

    public static void main(String[] args) {
        JFrame f = new KeyListenerF1Demo();
        f.setName("MyFrame");
        f.pack();
        f.setVisible(true);
    }

    @Override
    public boolean postProcessKeyEvent(KeyEvent ke) {
        // Check for function key F1 pressed.
        if (ke.getID() == KeyEvent.KEY_PRESSED
                && ke.getKeyCode() == KeyEvent.VK_F1) {

            // Get top level ancestor of focused element.
            Component c = ke.getComponent();
            while (null != c.getParent())
                c = c.getParent();

            // Output some help.
            System.out.println("Help for " + c.getName() + "."
                    + ke.getComponent().getName());

            // Tell keyboard focus manager that event has been fully handled.
            return true;
        }

        // Let keyboard focus manager handle the event further.
        return false;
    }
}

작업 예의 경우 가져 오기 추가를 고려할 수 있습니다. 나는 보통 '패키지 가져 오기'를 추가하여 짧게 유지합니다. 그렇지 않으면 +1. 흥미로운 기술.
Andrew Thompson

2

흠 .. 생성자는 어떤 클래스입니까? 아마도 JFrame을 확장하는 클래스일까요? 물론 창 초점은 창에 있어야하지만 그게 문제라고 생각하지 않습니다.

코드를 확장하고 실행하려고했지만 작동했습니다. 키를 누르면 인쇄 출력이됩니다. (Eclipse를 통해 Ubuntu로 실행) :

public class MyFrame extends JFrame {
    public MyFrame() {
        System.out.println("test");
        addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                System.out.println("tester");
            }

            public void keyReleased(KeyEvent e) {
                System.out.println("2test2");
            }

            public void keyTyped(KeyEvent e) {
                System.out.println("3test3");
            }
        });
    }

    public static void main(String[] args) {
        MyFrame f = new MyFrame();
        f.pack();
        f.setVisible(true);
    }
}

나는 또한 모든 메시지 출력을 얻습니다. Windows 명령 줄에서 실행합니다.
Darrel

2
이 예제에서는 JFrame에 포커스가 있기 때문에 모든 메시지를받습니다. JFrame에 TextBox 구성 요소를 추가하고 어떤 일이 발생하는지 확인하십시오.
bruno conde

2

이것은 도움이 될 것입니다

    yourJFrame.setFocusable(true);
    yourJFrame.addKeyListener(new java.awt.event.KeyAdapter() {


        @Override
        public void keyTyped(KeyEvent e) {
            System.out.println("you typed a key");
        }

        @Override
        public void keyPressed(KeyEvent e) {
            System.out.println("you pressed a key");
        }

        @Override
        public void keyReleased(KeyEvent e) {
            System.out.println("you released a key");
        }
    });

1

나는 같은 문제를 겪고 있습니다. 나는 Bruno의 조언을 따랐고 JFrame의 "첫 번째"버튼 (즉, 왼쪽 상단)에만 KeyListener를 추가하는 것이 트릭임을 발견했습니다. 그러나 나는 그것이 일종의 불안한 해결책이라는 것에 동의합니다. 그래서 나는 주위를 돌아 다니며 그것을 고칠 깔끔한 방법을 발견했습니다. 그냥 줄을 추가하십시오

myChildOfJFrame.requestFocusInWindow();

JFrame의 하위 클래스 인스턴스를 만들고 표시하도록 설정 한 후 기본 메서드에 추가합니다.


고마워, 같은 문제가 있었다. 이 ... 컨텐츠 구획 경우에도 이상한 구성 요소가 포커스를 잃을
Androbin

-3

ㅋㅋ .... 당신이해야 할 일은

addKeyListener (이);

코드에 올바르게 배치됩니다.


8
이것이 유용한 답변이되도록 "올바른 장소"를 설명해야합니다.
까지

-3

커스텀 JComponents가 부모 JFrame을 포커스 가능하게 설정하도록 할 수 있습니다.

생성자를 추가하고 JFrame을 전달하십시오. 그런 다음 paintComponent에서 setFocusable ()을 호출합니다.

이런 식으로 JFrame은 다른 구성 요소를 눌렀는지 여부에 관계없이 항상 KeyEvents를 수신합니다.


4
-1 확실히 아닙니다-그것은 하나 이상의 측면에서 완전한 <강력한 단어 검열>입니다 : a) 음란 한 하위 분류 b) 음란 한 참조 통과 c) 그림을 그리는 동안 부적절한 상태 변경 d) ..
kleopatra
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.