如何在具有许多 JTextFields 的 Java Swing JFrame 实例中获取关键事件?
How to get a Key Event in a Java Swing JFrame instance which has many JTextFields?
我有一个 JFrame class,它实现了几个 JLabel 和 JTextFields,我想在焦点位于该 JFrame 上并且用户按下 F1 时执行一个操作。
我创建了以下 class 来处理 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 class 使用:
this.addKeyListener(new PropertiesKey(this));
我确信这实际上是附加的,因为我在创建密钥侦听器 class 时看到 System.out 消息。
虽然此策略适用于我有 AWT 框架的程序的另一个区域,但在填充有 JTextFields 的 JFrame 的这种特定情况下,我无法设法将 KeyEvent 传播到我的侦听器。
我怀疑 TextFields - JFrame 上的焦点将始终由一个 TextField 捕获 - 可能会拦截事件而不传播它。
如果是这种情况,我该如何解决?哪个 strategy/pattern 用于捕获 JFrame 级别的关键事件?
事实并非如此,我该如何进一步解决这个问题?
您不应该使用 KeyListener。只能为具有焦点的组件生成按键事件。框架不会有直接焦点,只有一个组件添加到框架。
您应该使用 Key Bindings
。使用键绑定,即使组件没有焦点,您也可以将 Keystroke
映射到 Action
。确保使用适当的 InputMap
.
在这种情况下,如果您想为框架添加一个通用处理程序,您可以将键绑定添加到框架的 "root pane"。
阅读 How to Use Key Bindings 上的 Swing 教程部分了解更多信息。
另请阅读有关 How to Use Actions 的部分,了解使用 Action
的好处。
KeyListener
仅适用于(在大多数情况下)当前获得焦点的组件。如果您将它添加到焦点组件的容器中,以防该组件使用关键事件,它也将不起作用。注册键盘操作将是处理 window 范围热键的更好方法。
这是一个如何完成的小例子:
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 );
}
} );
}
}
请注意,我在此处的 JFrame
的 JRootPane
上注册了热键,但这通常无关紧要,因为条件是 JComponent.WHEN_IN_FOCUSED_WINDOW
- 这意味着您可以在window 中的任何组件,只要 window 集中在系统中,您就会收到操作事件。
或者,如果您的应用程序 JMenuBar
的菜单项可以执行您想要的操作 - 您可以为这些菜单项指定快捷键,它们将根据指定的热键自行处理操作。
我还建议阅读其他答案中提供的 Swing 教程 camickr 中的文章。
我有一个 JFrame class,它实现了几个 JLabel 和 JTextFields,我想在焦点位于该 JFrame 上并且用户按下 F1 时执行一个操作。
我创建了以下 class 来处理 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 class 使用:
this.addKeyListener(new PropertiesKey(this));
我确信这实际上是附加的,因为我在创建密钥侦听器 class 时看到 System.out 消息。
虽然此策略适用于我有 AWT 框架的程序的另一个区域,但在填充有 JTextFields 的 JFrame 的这种特定情况下,我无法设法将 KeyEvent 传播到我的侦听器。
我怀疑 TextFields - JFrame 上的焦点将始终由一个 TextField 捕获 - 可能会拦截事件而不传播它。
如果是这种情况,我该如何解决?哪个 strategy/pattern 用于捕获 JFrame 级别的关键事件?
事实并非如此,我该如何进一步解决这个问题?
您不应该使用 KeyListener。只能为具有焦点的组件生成按键事件。框架不会有直接焦点,只有一个组件添加到框架。
您应该使用 Key Bindings
。使用键绑定,即使组件没有焦点,您也可以将 Keystroke
映射到 Action
。确保使用适当的 InputMap
.
在这种情况下,如果您想为框架添加一个通用处理程序,您可以将键绑定添加到框架的 "root pane"。
阅读 How to Use Key Bindings 上的 Swing 教程部分了解更多信息。
另请阅读有关 How to Use Actions 的部分,了解使用 Action
的好处。
KeyListener
仅适用于(在大多数情况下)当前获得焦点的组件。如果您将它添加到焦点组件的容器中,以防该组件使用关键事件,它也将不起作用。注册键盘操作将是处理 window 范围热键的更好方法。
这是一个如何完成的小例子:
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 );
}
} );
}
}
请注意,我在此处的 JFrame
的 JRootPane
上注册了热键,但这通常无关紧要,因为条件是 JComponent.WHEN_IN_FOCUSED_WINDOW
- 这意味着您可以在window 中的任何组件,只要 window 集中在系统中,您就会收到操作事件。
或者,如果您的应用程序 JMenuBar
的菜单项可以执行您想要的操作 - 您可以为这些菜单项指定快捷键,它们将根据指定的热键自行处理操作。
我还建议阅读其他答案中提供的 Swing 教程 camickr 中的文章。