[java] JFrame 용 응답하지 않는 KeyListener

나는를 구현하기 위해 노력하고있어 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이벤트를 수신하지 않습니다. 그러나 나는 그것이 확실합니다.

내가 놓친 것이 있습니까?



답변

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

과정은 동일합니다.

myComponent.addKeyListener(new KeyListener ...);

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

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

myComponent.setFocusable(true);


답변

당신은 모든 구성 요소에 리스너를 등록하지 않으려면,
당신은 할 수 자신을 추가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);
    }
}


답변

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);


답변

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

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

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


답변

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

JFrame.setFocusable(true);

행운을 빕니다


답변

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;
}


답변

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;
    }
}