Java 2D Game:repaint();使窗口变灰

时间:2013-10-27 16:58:28

标签: java swing paint repaint

我正在尝试用Java制作2D游戏,但是当我在一个线程中调用repaint()方法时,会出现一个奇怪的灰色窗口。

这是我到目前为止的源代码:

  1. Spaceshooter.java

    package spaceshooter;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    public class Spaceshooter extends JFrame implements KeyListener, Runnable {
    
    private Player player = new Player(5, 186, this);
    private boolean up, down;
    
    public Spaceshooter(String title) {
        super(title);
        this.setFocusable(true);
        this.addKeyListener(this);
    }
    
    @Override
    public void paint(Graphics gr) {
        super.paint(gr);
    
        gr.setColor(Color.BLACK);
        gr.fillRect(0, 0, 800, 500);
    
        player.paintPlayer(gr);
    }
    
    public static void main(String[] args) {
        Spaceshooter shooter = new Spaceshooter("Spaceshooter");
        new Thread(shooter).start();
        shooter.setSize(800,500);
        shooter.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        shooter.setVisible(true);
    }
    
    @Override
    public void keyTyped(KeyEvent e) {
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == 38) {
            up = true;
            down = false;
        } else if (e.getKeyCode() == 40) {
            down = true;
            up = false;
        }
    }
    
    @Override
    public void keyReleased(KeyEvent e) {
        down = false;
        up = false;
    }
    
    @Override
    public void run() {
        while(true) {
            if (up) {
                player.moveUp();
            } else if (down) {
                player.moveDown();
            }
            repaint();
        try {
            Thread.sleep(20);
        } catch (InterruptedException ex) {
            Logger.getLogger(Spaceshooter.class.getName()).log(Level.SEVERE, null, ex);
        }
        }
    }
    }
    
  2. Player.java

     package spaceshooter;
    
     import java.awt.Component;
     import java.awt.Graphics;
     import java.awt.Toolkit;
    
     public class Player {
    
    private int x, y;
    private Component comp;
    
    public Player(int x, int y, Component comp) {
        this.x = x;
        this.y = y;
        this.comp = comp;
    }
    
    public void moveUp() {
        y -= 5;
    }
    
    public void moveDown() {
        y += 5;
    }
    
    public void paintPlayer(Graphics gr) {
        gr.drawImage(Toolkit.getDefaultToolkit().getImage("images/player.png"), x, y, comp);
    }
    
    }
    
  3. 提前感谢您的回答!

1 个答案:

答案 0 :(得分:2)

什么是EDT?

Swing事件处理代码在称为事件派发线程的特殊线程上运行。大多数调用Swing方法的代码也在这个线程上运行。这是必要的,因为大多数Swing对象方法都不是“线程安全的”。所有与GUI相关的任务,都应该对GUI进行任何更新,而绘制过程必须在EDT上进行,这涉及将请求包装在事件中并将其处理到EventQueue。然后,事件将从一个接一个的队列中按顺序分派,即FIRST IN FIRST OUT。也就是说,如果是,如果Event AEventQueue之前排队到Event B,那么事件B将不会在事件A之前被调度。

您执行的任何可能需要一段时间的任务,可能会阻止EDT,不会发生任何调度,也不会进行更新,因此您的应用程序会冻结。你将不得不杀死它以摆脱这种冰冻状态。

在你的程序中,除了创建你的JFrame并使其从主线程(我们也不应该这样做)可见之外:

    while(true) {
        if (up) {
            player.moveUp();
        } else if (down) {
            player.moveDown();
        }
        repaint();
    try {
        Thread.sleep(20);
    } catch (InterruptedException ex) {
        Logger.getLogger(Spaceshooter.class.getName()).log(Level.SEVERE, null, ex);
    }
    }

您正在发送repaint()请求,该请求会在您之后立即发送给您睡觉的线程。

<强> SwingUtilities.invokeLater():

Swing为向EDT发布SwingUtilities.invokeLater(new Runnable(){})请求提供了一个很好的功能repaint。你所要做的就是写:

    SwingUtilities.invokeLater(new Runnable()
       {
         public void run()
         {
               repaint();
         }
   });

现在还要提一下:

  1. 我们不应该使用Runnable实现GUI组件。创建另一个实现Runnable的类,在其中进行计算,然后使用SwingUtilities发布组件更新请求。
  2. 我们不应该直接在JFrame上进行自定义绘画。 JFrame是一个顶级组件。它更像是一个包含整个应用程序的容器。如果您想要自定义绘画,请使用自定义组件MyCanvas extends JComponent
  3. 我们不应该覆盖paint()函数。相反,paintComponent(g)将很好地服务于我们的自定义绘画目的。
  4. 学习使用Swing Timer类进行及时重复的GUI渲染任务。
  5. 教程资源和参考:

    1. The Event Dispatch Thread
    2. EventQueue
    3. How to Use Swing Timers
    4. Lesson: Performing Custom Painting