在二维JPanel[][]表格上使用KeyListener

3
我创建了一个二维的JPanel表格,并在第一个单元格上有一个JButton。我想用箭头键在我的表格边界内移动按钮。我需要在每个单元格或按钮上放置KeyListener吗?也许你会觉得我的问题很愚蠢,但我需要一点关于KeyListener的帮助。谢谢!这就是我需要创建的东西 这是我编写的代码!
public class MyFrame extends JFrame {

JPanel [][] innerCells;

public MyFrame() {
    JFrame fr = new JFrame("Final Exams");
    fr.setSize(800, 600);

    fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    fr.setVisible(true);
    fr.setLocationRelativeTo(null);

    JPanel p = new JPanel(new GridLayout(10, 10));
    JButton b = new JButton("G");
    innerCells = new JPanel[10][10];

    for(int i=0;i<10;i++){
        for(int j=0;j<10;j++){
            innerCells[i][j] = new JPanel();
            innerCells[i][j].setBorder(BorderFactory.createLineBorder(Color.orange));
            p.add(innerCells[i][j]);
        }
    }
    innerCells[0][0].add(b);
    fr.add(p);

}

2
看一下这个链接:http://stackoverflow.com/questions/16834765/move-jbutton-with-keyboard-arrows-inside-a-grid-panel/16835242#16835242。基本上,忽略KeyListener并使用key bindings。参考链接:http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html。 - MadProgrammer
非常感谢!我会处理这个问题并发布我的答案!;) 所以你的意思是没有监听器?为什么键绑定更好呢? - Manolis Karagiannis
2个回答

1

向按钮添加键盘监听器(使用KeyBindings更好)。

创建两个int变量,用于当前面板的索引(例如x,y)。

在keyPressed(KeyEvent e)方法中,从当前面板中删除按钮并将其添加到新面板中。

注意:如果要使用键移动按钮,则必须使按钮具有焦点。

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MyFrame extends JFrame {

    private JPanel [][] innerCells;
    private JButton b = new JButton("G");
    private int x=0;
    private int y=0;
    private final int size=10;

    public MyFrame() {
        JFrame fr = new JFrame("Final Exams");
        fr.setSize(800, 600);

        fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fr.setVisible(true);
        fr.setLocationRelativeTo(null);

        JPanel p = new JPanel(new GridLayout(size, size));

        innerCells = new JPanel[size][size];

        for(int i=0;i<size;i++){
            for(int j=0;j<size;j++){
                innerCells[i][j] = new JPanel();
                innerCells[i][j].setBorder(BorderFactory.createLineBorder(Color.orange));
               p.add(innerCells[i][j]);
            }
        }
        innerCells[0][0].add(b);
        fr.add(p);  

        b.addKeyListener(new KListener());
    }

    private class KListener extends KeyAdapter{
        public void keyPressed(KeyEvent e){
            innerCells[x][y].remove(b);
            innerCells[x][y].repaint();
            int keyCode = e.getKeyCode();
            switch( keyCode ) { 
                case KeyEvent.VK_UP:
                    x= x-1;
                        break;

                case KeyEvent.VK_DOWN:
                    x= (x+1)%size;
                        break;

                case KeyEvent.VK_LEFT:
                    y= y-1;
                        break;
                case KeyEvent.VK_RIGHT :
                    y= (y+1)%size; 
                        break;
            }
            if(x<0) x=size-1;
            if(y<0)y=size-1;
            innerCells[x][y].add(b);

            innerCells[x][y].revalidate();
            b.requestFocus();
    }
   ´        }

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

1
  1. 你尝试过@MadProgrammer评论中提供的链接代码吗?
  2. JFrame默认不会对KeyListener的KeyEvents做出反应,必须从AWTEventListener重新分派。
  3. 不要为简单的KeyEvents使用KeyListener,而是使用简单的KeysShortCuts。
- mKorbel
1
@Manolis Karagiannis请忽略此答案,使用带有图标的JLabel(而不是在JPanels之间移动真实的JButton),为MouseEvents添加MouseListener,为setIcon(IconLooksLikeAsBtton)和setIcon(null)之间的切换添加KeyBindings。 - mKorbel
1
@Manolis Karagiannis 如果不使用 doLayout() 和 notify(),那么这段代码永远不会正确工作,当然,使用 revalidate() 和 repaint() 会更好。 - mKorbel
1
@Manolis Karagiannis(谈论KeyListener和KeyBindings)在网格中的JPanel中,只有一个JPanel可以设置JPanel.setFocusable(true)或添加KeyBindings,只有包含JButton的JPanel才会被添加,其他的必须改为JPanel.setFocusable(false)。2. 从一个JPanel中移除JButton,然后稍后将JButton添加到JPanel中,无需重新验证和重绘,错误地将JButtons放置在所有JPanels中,并且只使用setVisible(true/false)进行操作。 - mKorbel
1
不是正确的做法,除非有重要原因,否则不要使用低级别的监听器。 重要原因将是使用三个或多个键同时按下/释放的快捷键。 如果没有重要原因,则尽可能使用顶层抽象。 在这种情况下是KeyBindings,在Oracle教程中有更多信息:-)。 JComponents必须是可聚焦或聚焦所有者才能用于KeyListener,否则您将成为焦点猎人,专注于在KeyBindings中实现的可设置参数。 乍一看,KeyListener更容易,但只有相同功能的代码更长。 - mKorbel
显示剩余9条评论

0
大家好,我终于解决了这个问题!以下是解决方案。我使用了KeyListener来完成,但像@MadProgrammer所说的那样,使用键绑定会更容易!
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class Askhsh6 {

    int gr, st;
    Dimension dim;

    public Askhsh6() {
        final JFrame fr1 = new JFrame("a Title");
        fr1.setSize(800, 600);
        fr1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fr1.setVisible(true);
        fr1.setResizable(false);

        final JButton b = new JButton("G");
        dim = new Dimension(70, 50);
        b.setSize(dim);
        b.setFocusable(false);
        b.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                b.validate();
                b.repaint();
                boolean pop = b.isFocusOwner();

                pop = b.isFocusOwner();
                System.out.println("" + pop);
            }
        });
        final JPanel[][] p;
        JPanel p1 = new JPanel();
        p1.setLayout(new GridLayout(8, 6));

        p = new JPanel[8][6];

        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 6; j++) {
                p[i][j] = new JPanel();
                p[i][j].setLayout(new BorderLayout());

                p[i][j].setBorder(BorderFactory.createLineBorder(Color.orange));
                p1.add(p[i][j]);

            }
        }
        p[0][0].add(b, BorderLayout.CENTER);
        gr = st = 0;

        fr1.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent ke) {
                if (ke.getKeyCode() == KeyEvent.VK_DOWN) {
                    System.out.println("DOWN");
                    if (gr + 1 < 8) {
                        p[gr][st].remove(b);
                        gr = gr + 1;
                        p[gr][st].add(b, BorderLayout.CENTER);

                        fr1.repaint();
                    }
                }
                if (ke.getKeyCode() == KeyEvent.VK_UP) {
                    System.out.println("UP");
                    if (gr - 1 >= 0) {
                        p[gr][st].remove(b);
                        gr = gr - 1;
                        p[gr][st].add(b, BorderLayout.CENTER);

                        fr1.repaint();
                    }
                }
                if (ke.getKeyCode() == KeyEvent.VK_LEFT) {
                    System.out.println("LEFT");
                    if (st - 1 >= 0) {
                        p[gr][st].remove(b);
                        st = st - 1;
                        p[gr][st].add(b, BorderLayout.CENTER);

                        fr1.repaint();
                    }
                }
                if (ke.getKeyCode() == KeyEvent.VK_RIGHT) {
                    System.out.println("RIGHT");
                    if (st + 1 < 6) {
                        p[gr][st].remove(b);
                        st = st + 1;
                        p[gr][st].add(b, BorderLayout.CENTER);

                        fr1.repaint();
                    }
                }
            }
        });
        fr1.add(p1);
        fr1.validate();
    }
}

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