Java:在单击按钮(没有注册事件侦听器)后,JPanel无法接收键事件?

4
首先,感谢您抽出时间阅读我的问题,我很感激。
以下是我目前的情况概述:
我正在编写一个滑块拼图游戏,使用按钮作为网格单元,大小为3 x 3。我已经在包含这些按钮的JPanel上添加了键盘监听器,它们对键盘事件做出了良好的响应。
然而,问题有点奇怪,我还没有真正能够确定为什么会出现这种不稳定的行为。在单击其中一个没有注册事件监听器的“按钮”之后,没有任何按钮移动,但是当您跟随按键事件时,按键变得无响应。
我的问题是:我知道这相当模糊,但这是否让任何人想起Java问题,还是听起来像是我的错误代码导致了所有这些问题?
我真的很乐意听取任何建议,因为这个问题已经困扰我大约一周了,我仍然不知道是什么原因引起的。
再次感谢您抽出时间查看此内容。
@trashgod: 是的,当然。
public class Test2 extends JPanel{
    JButton a = new JButton("A");

    Test2(){
        setFocusable(true);
        // Set layout to grid layout
        setLayout(new GridLayout(3, 3));
        // Add button
        //a.setEnabled(false);
        add(a);

        // Register key event which shifts it to the next cell when the right arrow is pressed
        addKeyListener(new KeyAdapter(){
            public void keyPressed(KeyEvent e){
                if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                    remove(a);
                    JButton b = new JButton("B");
                    //b.setEnabled(false);
                    add(b);
                    add(a);
                    validate();

                }
            }
        });
    }
}

代码片段的功能:JPanel接收键盘事件,准确地说是左箭头键,删除按钮'a',然后每次添加一个新的按钮'b',并跟随按钮'a'。但是,如果您尝试运行程序,点击按钮后,它就停止监听键盘事件了。

我刚刚思考了一下,这可能与JPanel中失去焦点有关吗?如果是这样,我应该注意哪些特定的方法来恢复失去的焦点呢?

谢谢!

(顺便说一句,setEnabled注释是我尝试解决这个问题的方法,只需禁用按钮,但仍无法解释如何将焦点恢复到JPanel中,如果这是问题所在。)


2
请提供一个 sscce,展示您所描述的问题。 - trashgod
请注意,SSCCE 应包括导入。顺便说一下,“按右箭头时进入下一个单元格”是指 KeyEvent.VK_LEFT 文档中“非小键盘左箭头键的常量”的哪个部分让您感到困惑?在代码中包含注释时,请确保它们与代码本身匹配。 ;) - Andrew Thompson
@AndrewThompson:感谢您阅读我的问题,是的,我知道它是左箭头键。评论出了错,我太傻了,谢谢您的提醒! :P 然而,令我担心的是,在按钮被按下后,JPanel 无法接收到键盘事件,这很容易通过为按钮添加 ActionListener 并在单击时将焦点恢复到 JPanel 来解决。再次感谢! :D - imicrothinking
2个回答

3
我们可以通过在每个按钮上调用setFocusable(false)来保持对JPanel的聚焦: button1.setFocusable(false); 或者 button2.setFocusable(false); 等等。
这将使添加了keyListeners的JPanel保持聚焦。

2

并非所有键都可以通过 KeyListener 访问,其中一些被注册为内置快捷方式以用于 JComponents,这取决于 JComponent 的类型和所使用的 Look and Feel。如果您想要监听来自键盘的 Keys,则必须实现 KeyBindings,Swing JComponents 指定使用此监听器而不是 KeyListener

按键 A 的工作示例:

import java.awt.GridLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Test2 extends JPanel {

    private static final long serialVersionUID = 1L;
    private JButton a = new JButton("A");

    public Test2() {
        setFocusable(true);
        setLayout(new GridLayout(3, 3));
        a.setEnabled(false);
        add(a);
        addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_A) {
                    remove(a);
                    JButton b = new JButton("B");
                    add(b);
                    add(a);
                    revalidate();
                    repaint();
                }
            }
        });
    }

    public static void main(String... args) {
        JFrame frame = new JFrame("");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new Test2());
        frame.pack();
        frame.setVisible(true);
    }
}

感谢您抽出时间来编辑我的代码。我最初已经测试了代码,最开始也认为无法接收箭头键,所以我也切换到更广泛接受的字符,例如“A”。然而,我的问题实际上是关于面板上的那些按钮。一旦您点击它们,JPanel就无法接收键盘事件。现在我知道原因了。这是因为它失去了焦点。只需为按钮添加一个动作监听器,即可将焦点恢复到JPanel,并且一切都设置好了。再次感谢! :D - imicrothinking
@imicrothinking_只需将动作监听器添加到按钮上,以将丢失的焦点恢复到JPanel,并设置一切就行了_。尽管看起来“有效”,但那只是不正确的做法……正如您已经发现的那样,KeyListener不是服务于您要求的适当工具(实际上,在Swing中从来不是合适的工具)。相反,使用Keybindings。 - kleopatra
@kleopatra很有趣,因为在我们的时间限制和目前对Java的了解下,我已经尝试了几种方法来解决这个问题。另一个流行的替代方法是广泛使用paintComponent方法来重绘许多许多行以模拟“瓷砖”,但是对我来说太过繁琐。老实说,我们项目的规格书要求游戏能够接收键盘事件,但编写代码并不直观。我稍后会考虑KeyBindings作为一种替代方案。谢谢~ - imicrothinking

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接