Как получить ключевое событие в экземпляре Java Swing JFrame, который имеет много полей JTextFields? - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть класс JFrame, который реализует несколько JLabels и JTextFields, и я хотел бы выполнить действие, когда фокус находится на этом JFrame, а пользователь нажимает F1.

Я создал следующий класс для обработкиKeyListener:

public class PropertiesKey implements KeyListener, ActionListener {

    private Properties propertiesWindow;

    public PropertiesKey(Properties p) {
        propertiesWindow = p;
        System.out.println("DEBUG PropertiesKey");
    }

    @Override
    public void keyPressed(KeyEvent event) {

        System.out.println("DEBUG keyPressed");
        // F1 - Display Attribute Window
        if (event.getKeyCode() == KeyEvent.VK_F1){ 
            System.out.println("F1");
            if(propertiesWindow.isVisible()) {
                propertiesWindow.setVisible(false);
            } else {
                propertiesWindow.setVisible(true);
            }
        }
        System.out.println("KEY PRESSED " + event);
    }

    @Override
    public void keyReleased(KeyEvent event) {
        System.out.println("KEY RELEASED " + event);
    }

    @Override
    public void keyTyped(KeyEvent event) {
        System.out.println("KEY TYPED " + event);
    }

    @Override
    public void actionPerformed(ActionEvent event) {
        System.out.println("ACTION PERFORMED " + event);
    }

}

Который я присоединяю к основному классу JFrame, используя:

this.addKeyListener(new PropertiesKey(this));

Я уверен, что это на самом деле присоединено, поскольку я вижу сообщение System.out, когда слушатель Keyкласс создан.

Хотя эта стратегия работает в другой области программы, где у меня есть кадр AWT, мне не удается передать KeyEvent моему слушателю в этом конкретном случае JFrame, заполненного JTextFields.

Я подозреваю, что TextFields - фокус на JFrame всегда будет захватываться одним TextField - может перехватывать событие и не распространять его.

Если это так, как я могупочини это? Какая стратегия / шаблон используется для захвата ключевых событий на уровне JFrame?

Если это не так, как я могу дополнительно устранить эту проблему?

Ответы [ 2 ]

1 голос
/ 05 ноября 2019

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

Вместо этого вы должны использовать Key Bindings. С помощью привязок клавиш вы можете сопоставить Keystroke с Action, даже если компонент не имеет фокуса. Убедитесь, что вы используете соответствующий InputMap.

. В этом случае, если вы хотите добавить общий обработчик для фрейма, вы бы добавили привязки клавиш к «корневой панели» фрейма.

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

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

0 голосов
/ 05 ноября 2019

KeyListener работает (в большинстве случаев) только для компонентов, которые в данный момент сосредоточены. Это также не будет работать, если вы добавите его в контейнер целевого компонента в случае, когда этот компонент потребляет ключевые события. Регистрация действия клавиатуры была бы лучшим способом доступа к горячим клавишам всего окна.

Вот небольшой пример того, как это можно сделать:

public class FrameHotkey
{
    public static void main ( final String[] args )
    {
        SwingUtilities.invokeLater ( new Runnable ()
        {
            @Override
            public void run ()
            {
                final JFrame frame = new JFrame ();

                frame.setLayout ( new FlowLayout ( FlowLayout.CENTER, 15, 15 ) );
                frame.add ( new JLabel ( "Field 1:" ) );
                frame.add ( new JTextField ( "Field 1", 15 ) );
                frame.add ( new JLabel ( "Field 2:" ) );
                frame.add ( new JTextField ( "Field 2", 15 ) );

                // Hotkey for the F1 in window
                frame.getRootPane ().registerKeyboardAction ( new ActionListener ()
                {
                    @Override
                    public void actionPerformed ( final ActionEvent e )
                    {
                        JOptionPane.showMessageDialog ( frame, "F1 have been pressed!" );
                    }
                }, KeyStroke.getKeyStroke ( KeyEvent.VK_F1, 0 ), JComponent.WHEN_IN_FOCUSED_WINDOW );

                frame.setDefaultCloseOperation ( WindowConstants.EXIT_ON_CLOSE );
                frame.pack ();
                frame.setLocationRelativeTo ( null );
                frame.setVisible ( true );
            }
        } );
    }
}

Обратите внимание, что я регистрирую горячую клавишуна JRootPane из JFrame здесь, но, как правило, это не имеет значения, потому что условие JComponent.WHEN_IN_FOCUSED_WINDOW - это означает, что вы можете зарегистрировать его на любом компоненте в окне, и пока окно сосредоточено в системе, вы будетеполучить событие action.

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

Я также рекомендую прочитать статью из учебника по Swing camickr , предложенную в другом ответе.

...