简体   繁体   中英

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

I wrote a code that generates the "snake" in Snake game for practice. (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. )

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

public void run()

method. Like this

try { Thread.sleep(delay); snakeBody.move(direction); 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. 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. In your example, changing the size and location of a JLabel triggers the repaint automatically.

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 .

  • It updates GUI components on a thread other than the event dispatch thread without synchronizing access to the shared data.

Instead, use a javax.swing.Timer to pace the animation. Your implementation of actionPerformed() will be called on the event dispatch thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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