Java 中的关键事件 - 初学者帮助

发布于 2024-09-19 12:33:04 字数 3581 浏览 6 评论 0原文

因此,我在学习 Java 的同时一直在编写一个简单的程序,该程序会显示一个小矩形屏幕,上面有一个正在移动的圆圈。背景和圆圈也会改变颜色和速​​度。

现在我正在尝试添加 KeyEvents,以便当用户键入字符时,圆圈将改变方向。我已经尝试了几个小时来掌握 KeyEvent 功能,但我陷入了困境。

如何更改以下代码以使程序响应键盘输入:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.JFrame;

public class MovingCircle3 extends JFrame implements ActionListener {

    Ellipse2D.Double myEllipse;
    Rectangle2D.Double backgroundRectangle;
    private int paintTally = 0;     // Counts # of repaints.
    private int timerSpeed = 500;   // Holds speed of timer. Initially: 500ms.
    private Timer timerOjbect;
    private char shapeMoveInput = 'd';

    public MovingCircle3() {
        myEllipse = new Ellipse2D.Double(30, 30, 20, 20); // Ellipse starting point
        backgroundRectangle = new Rectangle2D.Double(0, 0, 400, 300); // Background.
        this.timerOjbect = new Timer(500, this);
        timerOjbect.start();                 //Creates and starts timer.
    }

    public static void main(String[] args) {
        System.out.print("Game Controls: \n  l = Move left. \n  r = Move right. \n  u = Move up. \n  d = Move down. \n    ENTER COMMAND: ");    // Game controls.

        MovingCircle3 b = new MovingCircle3();

        b.setVisible(true);
        b.setSize(400, 300);
        b.setVisible(true);
        b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void keyPressed(KeyEvent e) {
        try {
            shapeMoveInput = e.getKeyChar();
        } catch (Exception ex) {
            shapeMoveInput = 'd';
        }
    }

    public void actionPerformed(ActionEvent ae) {
        //This will be called by the Timer
        if (shapeMoveInput == 'l') {
            myEllipse.setFrame(myEllipse.getX() - 1, myEllipse.getY(), myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 x-pixel left 
        } else if (shapeMoveInput == 'r') {
            myEllipse.setFrame(myEllipse.getX() + 1, myEllipse.getY(), myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 x-pixel right
        } else if (shapeMoveInput == 'u') {
            myEllipse.setFrame(myEllipse.getX(), myEllipse.getY() - 1, myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 y-pixel up
        } else if (shapeMoveInput == 'd') {
            myEllipse.setFrame(myEllipse.getX(), myEllipse.getY() + 1, myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 y-pixel
        }
        repaint();
    }

    public void paint(Graphics g) {
        paintTally++; // Increments by one for every repaint().
        if (paintTally % 25 == 0) { // Take modulus 25 of paintTally to execute every 25 paints.
            timerSpeed = (int) (timerSpeed / 2);
            timerOjbect.setDelay(timerSpeed); // Divide speed by 2 and see to timer length.  
        }
        int isPaintTen = (int) (paintTally / 10);  // Divide current count by 10.
        Graphics2D g2 = (Graphics2D) g;
        if ((isPaintTen % 2) == 0) { // Take modulus to set if #/10 is odd or even.
            g2.setColor(Color.YELLOW);
            g2.fill(backgroundRectangle);
            g2.setColor(Color.RED);
            g2.draw(myEllipse);

        } else if ((isPaintTen % 2) == 1) {
            g2.setColor(Color.RED);
            g2.fill(backgroundRectangle);
            g2.setColor(Color.YELLOW);
            g2.draw(myEllipse);
        }
    }
}

So I've been working on a simple program while learning Java that brings up a small rectangular screen that has a circle moving around on it. The background and circle also change colors and speeds.

Now I'm trying to add KeyEvents, such that when the user types a character, the circle will change directions. I've been trying to get a handle on the KeyEvent feature for a few hours now, and I'm stuck.

How would you change the following code so that the program responds to the keyboard input:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.JFrame;

public class MovingCircle3 extends JFrame implements ActionListener {

    Ellipse2D.Double myEllipse;
    Rectangle2D.Double backgroundRectangle;
    private int paintTally = 0;     // Counts # of repaints.
    private int timerSpeed = 500;   // Holds speed of timer. Initially: 500ms.
    private Timer timerOjbect;
    private char shapeMoveInput = 'd';

    public MovingCircle3() {
        myEllipse = new Ellipse2D.Double(30, 30, 20, 20); // Ellipse starting point
        backgroundRectangle = new Rectangle2D.Double(0, 0, 400, 300); // Background.
        this.timerOjbect = new Timer(500, this);
        timerOjbect.start();                 //Creates and starts timer.
    }

    public static void main(String[] args) {
        System.out.print("Game Controls: \n  l = Move left. \n  r = Move right. \n  u = Move up. \n  d = Move down. \n    ENTER COMMAND: ");    // Game controls.

        MovingCircle3 b = new MovingCircle3();

        b.setVisible(true);
        b.setSize(400, 300);
        b.setVisible(true);
        b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public void keyPressed(KeyEvent e) {
        try {
            shapeMoveInput = e.getKeyChar();
        } catch (Exception ex) {
            shapeMoveInput = 'd';
        }
    }

    public void actionPerformed(ActionEvent ae) {
        //This will be called by the Timer
        if (shapeMoveInput == 'l') {
            myEllipse.setFrame(myEllipse.getX() - 1, myEllipse.getY(), myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 x-pixel left 
        } else if (shapeMoveInput == 'r') {
            myEllipse.setFrame(myEllipse.getX() + 1, myEllipse.getY(), myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 x-pixel right
        } else if (shapeMoveInput == 'u') {
            myEllipse.setFrame(myEllipse.getX(), myEllipse.getY() - 1, myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 y-pixel up
        } else if (shapeMoveInput == 'd') {
            myEllipse.setFrame(myEllipse.getX(), myEllipse.getY() + 1, myEllipse.getWidth(), myEllipse.getHeight());   //Move 1 y-pixel
        }
        repaint();
    }

    public void paint(Graphics g) {
        paintTally++; // Increments by one for every repaint().
        if (paintTally % 25 == 0) { // Take modulus 25 of paintTally to execute every 25 paints.
            timerSpeed = (int) (timerSpeed / 2);
            timerOjbect.setDelay(timerSpeed); // Divide speed by 2 and see to timer length.  
        }
        int isPaintTen = (int) (paintTally / 10);  // Divide current count by 10.
        Graphics2D g2 = (Graphics2D) g;
        if ((isPaintTen % 2) == 0) { // Take modulus to set if #/10 is odd or even.
            g2.setColor(Color.YELLOW);
            g2.fill(backgroundRectangle);
            g2.setColor(Color.RED);
            g2.draw(myEllipse);

        } else if ((isPaintTen % 2) == 1) {
            g2.setColor(Color.RED);
            g2.fill(backgroundRectangle);
            g2.setColor(Color.YELLOW);
            g2.draw(myEllipse);
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

野の 2024-09-26 12:33:04

1)你永远不应该(除非你真的知道你在做什么)重写JFrame的paint方法。自定义绘制是通过重写 JPanel 的 PaintComponent(...) 方法来完成的。然后将自定义面板添加到 JFrame。您在原始帖子的评论中给出了 Swing 教程的链接。请阅读“自定义绘画”部分以获取更多信息和工作示例。

2) 然后您需要将 KeyListener 添加到面板。但是,KeyEvent 仅传递给具有焦点的组件,因此您需要使用面板上的 setFocusable(...) 方法使面板可聚焦。

然而,KeyListener 并不是解决这个问题的正确方法。您应该使用比使用 KeyListener 灵活得多的键绑定。 Swing 教程中再次有一个关于“如何使用键绑定”的部分。

1) You should NEVER (unless you really know what you are doing) override the paint method of a JFrame. Custom painting is done by overriding the paintComponent(...) method of a JPanel. Then you add the custom panel to the JFrame. You where given a link to the Swing tutorial in the comments of your original posting. Read the section on Custom Painting for more information and working examples.

2) You would then need to add the KeyListener to the panel. However, KeyEvents are only passed to the component with focus so you need to make the panel focusable by using the setFocusable(...) method on the panel.

However, a KeyListener is not the proper way to solve this problem. You should be using Key Bindings which are far more flexible than using KeyListeners. Again there is a section in the Swing tutorial on "How to Use Key Bindings".

迷迭香的记忆 2024-09-26 12:33:04

嘿,您似乎需要一个 KeyListener,但 ActionListener 将在您的 JFrame 上工作。看起来您正在实现 ActionListener,它是关键侦听器的超类。您正确地实现了它,但之后您需要注册一个新的侦听器,这会导致 Swing 中的事件线程将事件发送到该侦听器。事件线程是系统管理的线程。您可以在 oracles/Suns 阅读此事件主题网站。另外,如果您有兴趣,它还使用观察者模式。

您需要做的就是在初始化 MovingCircle3() 中执行以下操作

this.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                movingcircle3_Function(e);
            }
        });  

,或者您可以尝试以下操作,但我不确定它是否可以正常工作

this.addActionListener(this);

Hey there it would seem you are in need of a KeyListener but ActionListener will work on your JFrame. It looks like you are implementing the ActionListener which is a superclass of the key listener. You are implementing it correctly but after that you need to register a new listener, this causes the Event thread in Swing to send events to this listener. The Event thread is a system managed thread. You can read up on this Event Thread at oracles/Suns website. Also just a side note it uses the Observer Pattern if you are interested.

All you need to do is in initialization MovingCircle3() do the following

this.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                movingcircle3_Function(e);
            }
        });  

or you could try the following but i am unsure if it would work properly

this.addActionListener(this);

和我恋爱吧 2024-09-26 12:33:04

阅读 InputMapActionMap。 (教程此处)将键盘敲击映射到ID,然后是调用方法的 ID。

Read up on InputMap and ActionMap. (tutorial here) It's a two-step process of mapping keyboard strokes to an ID and then IDs to calling a method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文