简体   繁体   English

如何将KeyListener与JFrame一起使用?

[英]How to use KeyListener with JFrame?

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. 所以,我试图使用KeyEventKeyListener )进行矩形移动,每当我尝试按下键时,矩形都不会移动。

The rectangle is drawn, but whenever I hit the left and right keys, nothing happens. 在绘制矩形,但每当我打的leftright按键,没有任何反应。 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. 我有两个类,一个是带有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! 提前致谢!

The rectangle is not moving because you are not using JFrame correctly. 由于您未正确使用JFrame因此矩形不会移动。 You have to assign frame to new mainFrame() instead of ignoring the instantiated mainFrame object. 您必须将frame分配给new mainFrame()而不是忽略实例化的mainFrame对象。

There are several other issues as @MadProgrammer points out. @MadProgrammer指出,还有其他几个问题。

Here is the code that fixes some of the issues: 以下是修复某些问题的代码:

mainFrame.java 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 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 SwingUtilities to put the gui update code because swing objects are not thread-safe. 顺便说一句,使用SwingUtilities来放置gui更新代码,因为swing对象不是线程安全的。

There are at least three issues... 至少有三个问题......

Firstly... 首先...

Your mainFrame class extends from JFrame , but in your main method, you create an instance of it and ignore it, by creating your own JFrame . 您的mainFrame类从JFrame extends ,但在您的main方法中,您可以通过创建自己的JFrame来创建它的实例并忽略它。

The KeyListener is registered to the instance of mainFrame , meaning, it's been ignored. KeyListener已注册到mainFrame的实例,这意味着它已被忽略。

You should get rid of extends JFrame as it's just confusing the issue 你应该摆脱extends JFrame因为它只是混淆了这个问题

Secondly... 其次...

KeyListener will 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 API with the Draw panel, this will allow you to over come the focus issues. 相反,您应该将键绑定API与“ Draw面板一起使用,这将允许您解决焦点问题。

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 paint and instead use paintComponent . 您应该避免重写paint ,而是使用paintComponent There are lots of reasons for this, but generally, it paints in the background, is called as updates to child components. 这有很多原因,但一般来说,它在后台绘制,称为子组件的更新。

Finally, make sure you are calling super.paintComponent before you do anything else, to ensure the Graphics context is prepared for painting 最后,确保在执行任何其他super.paintComponent之前调用super.paintComponent ,以确保为绘制准备Graphics上下文

Take a look at Performing Custom Painting for more details 有关更多详细信息,请参阅执行自定义绘画

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 /

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框架):

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

Method getAllComponents(frame); 方法getAllComponents(frame); Class Common is just a class, Class 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. 谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM