如何在JFrame中使用KeyListener?

17

我想让一个矩形通过 KeyEvent (KeyListener) 来移动,但每次按下键盘时,矩形都不会移动。

虽然矩形已经被绘制出来了,但是当我尝试按下 leftright 键时,没有任何反应。我有两个类,一个是带有keyEvents和frame的主类,另一个负责绘制矩形并保持移动函数。

以下是我的代码:

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;


public class mainFrame extends JFrame implements KeyListener{

mainDraw Draw = new mainDraw();

public void keyPressed(KeyEvent e) {

    int key = e.getKeyCode();

    if(key == KeyEvent.VK_D){

        Draw.moveRight();
    }
}

public void keyReleased(KeyEvent e) {


}
public void keyTyped(KeyEvent e) {}

public mainFrame()
{
    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(false);
}

public static void main(String[] args) {

    mainFrame M1 = new mainFrame();

    mainDraw Draw = new mainDraw();

    JFrame frame = new JFrame("Square Move Practice");


    //frame
    frame.setVisible(true);
    frame.setResizable(false);
    frame.setSize(600, 600);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(Draw);

}
}

现在开始第二个分类:

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JComponent;

public class mainDraw extends JComponent{

public int x = 50;
public int y = 50;

public void paint(Graphics g){

    g.drawRect(x, y, 50, 50);
    g.fillRect(x, y, 50, 50);
    g.setColor(Color.BLACK);
}

public void moveRight()
{
    x = x + 5;
    y = y + 0;
    repaint();
}

}

请告诉我如何移动矩形。

提前感谢!

4个回答

16

矩形不会移动,因为您没有正确使用JFrame。您必须将frame分配给new mainFrame(),而不是忽略已实例化的mainFrame对象。

正如@MadProgrammer指出的那样,还有其他几个问题。

以下是修复一些问题的代码:

mainFrame.java

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;


public class mainFrame extends JFrame implements KeyListener{
    private mainDraw draw;

    public void keyPressed(KeyEvent e) {
        System.out.println("keyPressed");
    }

    public void keyReleased(KeyEvent e) {
        if(e.getKeyCode()== KeyEvent.VK_RIGHT)
            draw.moveRight();
        else if(e.getKeyCode()== KeyEvent.VK_LEFT)
            draw.moveLeft();
        else if(e.getKeyCode()== KeyEvent.VK_DOWN)
            draw.moveDown();
        else if(e.getKeyCode()== KeyEvent.VK_UP)
            draw.moveUp();

    }
    public void keyTyped(KeyEvent e) {
        System.out.println("keyTyped");
    }

    public mainFrame(){
        this.draw=new mainDraw();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                mainFrame frame = new mainFrame();
                frame.setTitle("Square Move Practice");
                frame.setResizable(false);
                frame.setSize(600, 600);
                frame.setMinimumSize(new Dimension(600, 600));
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.getContentPane().add(frame.draw);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

mainDraw.java

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;

public class mainDraw extends JComponent {

    public int x = 50;
    public int y = 50;

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawRect(x, y, 50, 50);
        g.fillRect(x, y, 50, 50);
        g.setColor(Color.BLACK);
    }

    public void moveRight() {
        x = x + 5;
        repaint();
    }

    public void moveLeft() {
        x = x - 5;
        repaint();
    }

    public void moveDown() {
        y = y + 5;
        repaint();
    }

    public void moveUp() {
        y = y - 5;
        repaint();
    }
}

顺便提一下,使用SwingUtilities来放置GUI更新代码,因为Swing对象不是线程安全的。


7

至少有三个问题...

首先...

您的 mainFrameextendsJFrame,但在您的 main 方法中,您创建了一个实例并忽略了它,通过创建自己的 JFrame

KeyListener 已注册到 mainFrame 实例中,这意味着被忽略了。

您应该摆脱 extends JFrame,因为它只会混淆问题

其次...

KeyListener 只会在其注册到的组件是可聚焦的且直接获得焦点时响应键事件,这使其不可靠。

相反,您应该使用 key bindings APIDraw 面板一起使用,这将允许您克服焦点问题。

第三...

您已经破坏了绘画链,这意味着当矩形移动时,之前绘制的部分仍将保留。

您应该避免重写 paint,而应该使用 paintComponent。有很多原因,但通常在后台绘制,被调用作为子组件的更新。

最后,请确保在执行任何其他操作之前调用 super.paintComponent,以确保准备好用于绘画的 Graphics 上下文

请查看自定义绘画了解更多详细信息


0

你应该将监听器添加到mainDraw类中,而不是mainFrame。

最好不要在框架和窗口中处理键盘和鼠标事件。

o/


-1

我曾试图将快捷键监听器实现到整个框架中,但没有成功,最终找到了一种方法。如果你想在焦点转移到其他组件时仍然设置监听器,你必须将监听器添加到所有组件中。

这是我的代码:

在你的构造函数中调用此代码:

setShortcutListener(this); // this = JFrame when you call in in constructor

方法 setShortcutListener(JFrame frame) :

private void setShortcutListener(JFrame frame) {
    List<Component> comp_list = Common.getAllComponents(frame);
    for (Component component : comp_list) {
        component.addKeyListener(getShortcutKeyListener());
    }
}

方法 getAllComponents(frame);类 Common 只是一个类,

public static List<Component> getAllComponents(final Container c) {
    Component[] comps = c.getComponents();
    List<Component> compList = new ArrayList<Component>();
    for (Component comp : comps) {
        compList.add(comp);
        if (comp instanceof Container) {
            compList.addAll(getAllComponents((Container) comp));
        }
    }
    return compList;
}

方法 getShortcutKeyListener() :

public static KeyListener getShortcutKeyListener() {
    KeyListener listener = new KeyListener() {

        @Override
        public void keyReleased(KeyEvent evt) {
            if (evt.getKeyCode() == KeyEvent.VK_F3) {
                // What you do when F3 key pressed
            } else if (evt.getKeyCode() == KeyEvent.VK_F2) {
                // What you do when F2 key pressed
            } 
        }

        @Override
        public void keyTyped(KeyEvent e) {
            // Do nothing
        }

        @Override
        public void keyPressed(KeyEvent e) {
            // Do nothing
        }
    };
    return listener;
}

我认为我们有比这更简单的方法,但是这段代码完全按预期工作。键盘监听器可以在表单中的任何位置工作。

希望这个答案能帮助到某些人。谢谢。


你可以通过键绑定API更简单、更可靠地实现这一点。 - MadProgrammer

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