繁体   English   中英

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

[英]Java AWT/Swing When to use repaint() method?

我编写了一个代码来生成Snake游戏中的“ snake”进行练习。 (以防您不熟悉蛇游戏中的蛇,它是一条5盒长的蛇,其头部(由JLabel创建)和身体部位(也由JLabel创建)在头部之后。)

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()方法

公共无效run()

方法。 像这样

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

但是事实证明,没有它也可以正常工作。我已经阅读了许多有关repaint()的文章,但是当我需要使用它时我仍然听不懂。 谁能用菜鸟友好的术语解释一下? 谢谢 :)

每当RepaintManager尚未代表您调用repaint()时,就必须调用它,例如通过更新绑定属性(例如,文本或颜色)。 在您的示例中,更改JLabel的大小和位置会自动触发重新绘制。

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

  • 它在初始线程而不是事件分发线程上创建GUI。

  • 它在事件分配线程以外的其他线程上更新GUI组件,而不同步对共享数据的访问。

而是使用javax.swing.Timer来调整动画的速度。 您的actionPerformed()将在事件分配线程上调用。

暂无
暂无

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

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