Jpanel图形不能在可运行的内部移动

时间:2013-07-31 08:52:15

标签: java jpanel paint runnable

为什么我的椭圆形没有向右移动?我有一个游戏循环,但不知何故,圆圈停留在它出现的地方,而不是每个循环向右移动2个像素。 奇怪的是它在实际绘画之前进入循环。但随后图形对象出现(在固定位置)。

public class GamePanel extends JPanel implements Runnable {

    public static int WIDTH = 1024;
    public static int HEIGHT = WIDTH / 16 * 9;
    private Thread t1;
    boolean running;
    private int FPS = 60;
    private long optimalTime = 1000 / FPS;
    private int heroX = 200;
    private int heroY = 200;


    public void addNotify(){
        Dimension size = new Dimension(WIDTH,HEIGHT);
        setPreferredSize(size);
        setFocusable(true);
        requestFocus();
        running = true;
        t1 = new Thread(this);
        t1.start();
    }



    public void paintComponent (Graphics g){
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(Color.WHITE);
        g2.fillRect(0, 0, WIDTH, HEIGHT);
        g2.setColor(Color.BLACK);
        g2.fillOval(heroX, heroY, 50, 50);
        g2.dispose();
    }


    public void run() {
        long startTime;
        long passedTime;
        long waitTime;
        while (running){
            startTime = System.nanoTime();
            System.out.println("Runs");
            update();
            draw();
            repaint();
            passedTime = System.nanoTime() - startTime;
            waitTime = optimalTime - passedTime / 1000000;
            try {
                if (waitTime <= 0){
                    waitTime = 2;
                }
                Thread.sleep(waitTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }



    private void draw() {


    }



    private void update() {

        heroX += 2;

    }

}

2 个答案:

答案 0 :(得分:1)

你应该使用swing Timer而不是尝试使用线程。如果您需要在后台执行某些操作,请使用SwingWorkers。如果你真的需要(你需要一个扭曲的用户案例需要这样做),你可以使用自己的线程和摆动,但是在你很好地掌握线程使用swing的方式。

public class GamePanel extends JPanel {
    private static final int DELAY = 1000 / 60;
    private final Timer timer;
    // ...

    private int heroX = 200;
    private int heroY = 200;

    public GamePanel() {
        timer = new Timer(DELAY, new ActionListener() {
            @Override
            public void actionPerformed(final ActionEvent e) {
                update();
                repaint();
            }
        });
        // ...
    }

    // No need to make this public
    @Override
    protected void paintComponent (Graphics g) {
        // ...
    }

    @Override
    public Dimension getPreferredSize() {
        // Overriding is cleaner than using set*Size(). Search old questions to see why
    }

    public void startAnimation() {
         timer.start();
    }

    public void stopAnimation() {
         timer.stop();
    }

    // Remove addNotify() and run()
}

答案 1 :(得分:0)

阅读和测试后,我只想这样做。它可以按预期工作,即使paintComponent在EDT之外也是如此。

public class GamePanel extends JPanel implements Runnable {

    public static int WIDTH = 1024;
    public static int HEIGHT = WIDTH / 16 * 9;
    private int cordX = WIDTH / 2;
    private Thread t1;
    private boolean running = true;

    public void addNotify() {
       super.addNotify();
       Dimension size = new Dimension (WIDTH, HEIGHT);
       setPreferredSize(size);
       t1 = new Thread(this);
       t1.start();
     }

    public void paintComponent(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        g.setColor(Color.BLACK);
        g.fillOval(cordX, HEIGHT /2 , 20, 20);
    }

    public void run() {
        while(running) {
            cordX += 2;
            repaint();
            try {
                    Thread.sleep(17);
                } catch (InterruptedException e) {
                    e.printStackTrace();
            }
        }  
}