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

时间:2016-01-24 12:26:52

标签: java swing keylistener paintcomponent thread-sleep

我写了一个代码,在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()方法
  

public void run()

方法。 喜欢这个

  

尝试{Thread.sleep(延迟); snakeBody.move(方向);重绘(); }

但事实证明没有它就可以正常工作.. 我已经阅读了很多关于repaint()的帖子,但是当我需要使用它时我仍然没有得到。 有人可以用noob友好的术语解释吗?谢谢:))

1 个答案:

答案 0 :(得分:2)

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

更严重的是,您的示例在两个方面错误地同步:

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