Java AWT/Swing 何时使用 repaint() 方法?

标签 java swing keylistener paintcomponent thread-sleep

我编写了一个生成贪吃蛇游戏中的“蛇”的代码以供练习。 (如果您不熟悉贪吃蛇游戏中的蛇,它是一条 5 格长的蛇,有一个头部(使用 JLabel 创建)和跟随头部的 body 部位(也使用 JLabels 创建)。)

import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import javax.swing.*;

public class SnakeGameFrame extends JFrame {
    Thread snakeThread;
    GroundPanel p;
    public SnakeGameFrame() {
        super("Moving Snake!");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        p = new GroundPanel();
        setContentPane(p);
        setSize(400,400);
        setVisible(true);
        p.requestFocus();
        snakeThread = new Thread(p);
        snakeThread.start();
    }

    class GroundPanel extends JPanel implements Runnable{
        static final int LEFT = 0;
        static final int RIGHT = 1;
        static final int UP = 2;
        static final int DOWN = 3;
        int direction;
        Image img;
        SnakeBody snakeBody;
        final int delay = 200;
        public GroundPanel() {
            setLayout(null);
            snakeBody = new SnakeBody();
            snakeBody.addIn(this);
            direction = LEFT;
            this.addKeyListener(new MyKeyListener());
            ImageIcon icon = new ImageIcon("twilight.jpg");
            img = icon.getImage();
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(img, 0,0,getWidth(), getHeight(), null);
        }
        public void run() {
            while(true) {
                try {
                    Thread.sleep(delay);                
                    snakeBody.move(direction);
                }catch(InterruptedException e) {
                    return;
                }
            }
        }

        class MyKeyListener extends KeyAdapter {
            public void keyPressed(KeyEvent e) {
                switch(e.getKeyCode()) {
                case KeyEvent.VK_LEFT:
                    direction = LEFT;
                    break;
                case KeyEvent.VK_RIGHT:
                    direction = RIGHT;
                    break;
                case KeyEvent.VK_UP:
                    direction = UP;
                    break;
                case KeyEvent.VK_DOWN:
                    direction = DOWN;
                    break;
                }
            }
        }
    }

    class SnakeBody {
        Vector<JLabel> v = new Vector<JLabel>();

        public SnakeBody() {
            ImageIcon head = new ImageIcon("head.jpg");
            JLabel la = new JLabel(head);
            la.setSize(head.getIconWidth(), head.getIconHeight());
            la.setLocation(100, 100);
            v.add(la);

            ImageIcon body = new ImageIcon("body.jpg");     
            for(int i=1; i<10; i++) {
                la = new JLabel(body);
                la.setSize(body.getIconWidth(), body.getIconHeight());
                la.setLocation(100+i*20, 100);
                v.add(la);
            }
        }

        public void addIn(JPanel p) {
            for(int i=0; i<v.size(); i++)
                p.add(v.get(i));
        }

        public void move(int direction) {
            for(int i=v.size()-1; i>0; i--) {
                JLabel b = v.get(i);
                JLabel a = v.get(i-1);
                b.setLocation(a.getX(), a.getY());
            }
            JLabel head = v.get(0);
            switch(direction) {
            case GroundPanel.LEFT :
                head.setLocation(head.getX()-20, head.getY());
                break;
            case GroundPanel.RIGHT :
                head.setLocation(head.getX()+20, head.getY());
                break;
            case GroundPanel.UP :
                head.setLocation(head.getX(), head.getY()-20);
                break;
            case GroundPanel.DOWN :
                head.setLocation(head.getX(), head.getY()+20);
                break;
            }
        } 
    }

    public static void main(String[] args) {
        new SnakeGameFrame();
    }
}

我的问题是为了继续“更新”我的蛇,我想我必须在我的蛇中使用 repaint() 方法

public void run()

方法。 像这样

try { Thread.sleep(delay); snakeBody.move(direction); repaint(); }

但事实证明,没有它它也能正常工作.. 我读过很多关于 repaint() 的文章,但我仍然不知道何时需要使用它。 有人可以用菜鸟友好的术语解释一下吗?谢谢:)

最佳答案

只要 RepaintManager 尚未代表您执行此操作(例如更新文本或颜色等绑定(bind)属性),您就必须调用 repaint()。在您的示例中,更改 JLabel 的大小和位置会自动触发重绘。

更严重的是,您的示例以两种方式错误地同步:

相反,请使用 javax.swing.Timer调整动画的节奏。您的 actionPerformed() 实现将在事件调度线程上调用。

关于Java AWT/Swing 何时使用 repaint() 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34975768/

相关文章:

java - 拒绝 j_security_check 上的 GET 方法

java - 第一次尝试保存数据后,关闭程序后无法打开

java - KeyEvent 监听器中的多个键

java - 在哪里添加 KeyListener 以便 'always' 被监听

java - 如何在 Swing 中为 JTable 提供分页支持?

java - 错误 :Execution failed for task ':app:transformClassesWithMultidexlistForDebug' . >

Java邮件 : FolderClosedException coming frequently

java - 在 JOptionPane JPasswordField 中设置焦点

java - 如果我将 JPanel 和 JFrame 子类化,为什么我的 JFrame 保持为空?

java - Java 中不带焦点的情况下监听输入