Java 如何在 JFrame 中使用 KeyListener?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21997130/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 11:56:11  来源:igfitidea点击:

How to use KeyListener with JFrame?

javaswinganimationjframe

提问by user3183679

So, I was trying to make a rectangle move with a KeyEvent(KeyListener) and whenever I try to hit the key, the rectangle doesn't move.

所以,我试图用KeyEvent( KeyListener)移动矩形,每当我尝试按下键时,矩形都不会移动。

The rectangle is drawn, but whenever I hit the leftand rightkeys, nothing happens. I have two classes, one is my main class with the keyEvents and the frame and the other, draws the rectangle and holds the function to move the rectangle.

矩形已绘制,但每当我按下leftright键时,什么也没有发生。我有两个类,一个是带有 keyEvents 和框架的主类,另一个是绘制矩形并保存移动矩形的函数。

Here is my code:

这是我的代码:

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);

}
}

And now the second class:

现在是第二堂课:

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();
}

}

Please tell me how I can move the rectangle. Thanks in advance!

请告诉我如何移动矩形。提前致谢!

采纳答案by Jhonatan

The rectangle is not moving because you are not using JFramecorrectly. You have to assign frameto new mainFrame()instead of ignoring the instantiated mainFrameobject.

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

There are several other issues as @MadProgrammer points out.

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

Here is the code that fixes some of the issues:

以下是修复部分问题的代码:

mainFrame.java

主框架.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();
    }
}

BTW, use SwingUtilitiesto put the gui update code because swing objects are not thread-safe.

顺便说一句,用于SwingUtilities放置 gui 更新代码,因为 Swing 对象不是线程安全的。

回答by Jhonatan

You should add your listener in the mainDraw class, not your mainFrame.

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

It's a good practice not to handle key and mouse events in Frames and Windows.

在 Frames 和 Windows 中不处理键和鼠标事件是一个很好的做法。

o/

o/

回答by MadProgrammer

There are at least three issues...

至少有三个问题...

Firstly...

首先...

Your mainFrameclass extendsfrom JFrame, but in your mainmethod, you create an instance of it and ignore it, by creating your own JFrame.

您的mainFrameextends来自JFrame,但在您的main方法中,您通过创建自己的JFrame.

The KeyListeneris registered to the instance of mainFrame, meaning, it's been ignored.

KeyListener注册到的情况下mainFrame,这意味着,它被忽略。

You should get rid of extends JFrameas it's just confusing the issue

你应该摆脱,extends JFrame因为它只是混淆了问题

Secondly...

其次...

KeyListenerwill only respond to key events when the component it is registered to is focusable AND has direct focus, this makes it unreliable.

KeyListener只有当它注册到的组件是可聚焦的并且具有直接焦点时,才会响应关键事件,这使得它不可靠。

Instead, you should use the key bindings APIwith the Drawpanel, this will allow you to over come the focus issues.

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

Thirdly...

第三...

You've broken the paint chain, this means that when the rectangle moves, what was painted previously will still remain.

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

You should refrain from overriding paintand instead use paintComponent. There are lots of reasons for this, but generally, it paints in the background, is called as updates to child components.

您应该避免覆盖paint并使用paintComponent. 这有很多原因,但一般来说,它在后台绘制,被称为对子组件的更新。

Finally, make sure you are calling super.paintComponentbefore you do anything else, to ensure the Graphicscontext is prepared for painting

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

Take a look at Performing Custom Paintingfor more details

查看执行自定义绘画以了解更多详细信息

回答by Sahan

I was trying to implement shortcut listeners to whole frame and not succeeded, Finally found a way. If you want to set listener even when focus to another component, You must add listeners to all components.

我试图为整个框架实现快捷方式侦听器但没有成功,终于找到了方法。如果您想设置监听器,即使焦点在另一个组件上,您必须为所有组件添加监听器。

Here is my code,

这是我的代码,

Call this in your constructor :

在您的构造函数中调用它:

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

Method setShortcutListener(JFrame frame) :

方法 setShortcutListener(JFrame frame) :

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

Method getAllComponents(frame); Class Common is just a class,

方法 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;
}

Method getShortcutKeyListener() :

方法 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;
}

I think we have easy ways than this, But this code works exactly as expected. Key listeners works anywhere in form.

我认为我们有比这更简单的方法,但是这段代码完全按预期工作。关键侦听器以形式在任何地方工作。

Hope this answer will help someone. Thanks.

希望这个答案会对某人有所帮助。谢谢。