简体   繁体   English

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

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

I wrote a code that generates the "snake" in Snake game for practice. 我编写了一个代码来生成Snake游戏中的“ snake”进行练习。 (In case you aren't familiar with the snake in snake game, it's a 5-boxes long snake with a head(created with JLabel) and body parts(also created with JLabels) following the head. ) (以防您不熟悉蛇游戏中的蛇,它是一条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();
    }
}

My question is in order to keep "updating" my snake, I thought I would have to use the repaint() method in my 我的问题是为了继续“更新”我的蛇,我以为我必须在我的蛇中使用repaint()方法

public void run() 公共无效run()

method. 方法。 Like this 像这样

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

but it turned out that it works just fine without it.. I've read many posts about repaint() but I still don't get when I need to use it. 但是事实证明,没有它也可以正常工作。我已经阅读了许多有关repaint()的文章,但是当我需要使用它时我仍然听不懂。 Could anyone please explain in noob-friendly terminologies ? 谁能用菜鸟友好的术语解释一下? Thank you :) 谢谢 :)

You must invoke repaint() whenever the RepaintManager does not already do so on your behalf, as by updating a bound property such as text or color. 每当RepaintManager尚未代表您调用repaint()时,就必须调用它,例如通过更新绑定属性(例如,文本或颜色)。 In your example, changing the size and location of a JLabel triggers the repaint automatically. 在您的示例中,更改JLabel的大小和位置会自动触发重新绘制。

More seriously, your example is incorrectly synchronized in two ways: 更严重的是,您的示例通过两种方式错误地同步:

  • It creates the GUI on the initial thread rather than on the event dispatch thread . 它在初始线程而不是事件分发线程上创建GUI。

  • It updates GUI components on a thread other than the event dispatch thread without synchronizing access to the shared data. 它在事件分配线程以外的其他线程上更新GUI组件,而不同步对共享数据的访问。

Instead, use a javax.swing.Timer to pace the animation. 而是使用javax.swing.Timer来调整动画的速度。 Your implementation of actionPerformed() will be called on the event dispatch thread. 您的actionPerformed()将在事件分配线程上调用。

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

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