重绘JPanel

时间:2012-02-01 10:36:31

标签: java swing jpanel repaint concurrency

我想要重新绘制我的jPanel 我有一个App类来处理在这个JFrame中显示的屏幕我添加了一个处理所有JPanel的Board JPanel对象。 在董事会课上我有

ex = new Explosion(10, 10); 
new Thread(ex).start();

在我的Explosion课程中,我有一个构造函数来裁剪我的精灵文件,覆盖paint()和:

public void run()
    {
        while(cursor < (rows*cols))
        {
            repaint();

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(cursor);

            cursor++;
        }
    }

循环工作正常,但我的屏幕没有重新绘制,只显示第一张图像。

我该怎么做才能刷新?

由于

编辑: 这是我的代码:

public class Explosion extends JPanel implements Runnable{

private BufferedImage img;

final int width = 320;
final int height = 320;
final int rows = 5;
final int cols = 5;

private int x,y;

private int cursor;

BufferedImage[] sprites = new BufferedImage[rows * cols];

public Explosion(int x, int y)
{
    this.x = x;
    this.y = y;

    try {
        try {
            this.img = ImageIO.read(new File((this.getClass().getResource("files/explosion2.png")).toURI()));
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

    cursor = 0;

    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            sprites[(i * cols) + j] = img.getSubimage(
                i * (width/rows),
                j * (height/cols),
                width/rows,
                height/cols
            );
        }
    }
}

public void run()
{
    ActionListener taskPerformer = new ActionListener() {
          public void actionPerformed(ActionEvent evt) {
              cursor++;
              repaint();
          }
      };

    while(cursor < (rows*cols))
    {           
          new Timer(50, taskPerformer).start();


        if (cursor==(rows*cols)-1)
            cursor=0;
    }
}

public void paintComponent(Graphics g){
    System.out.println("paintComponent");
    Graphics2D g2d = (Graphics2D)g;
    g2d.drawImage(sprites[cursor], x, y, this);
    g.dispose();    
}

/*public void paint(Graphics g) {
        super.paint(g);

        System.out.println("paint");

        Graphics2D g2d = (Graphics2D)g;
        g2d.drawImage(sprites[cursor], x, y, this);
        Toolkit.getDefaultToolkit().sync();
        g.dispose();        
}*/


}
public class Main extends JFrame{

    public Main() 
    {
        Board board = new Board();
        add(board);
        setTitle("Explosion");
        setSize(500, 500);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);  
    }

    public static void main(String[] args) {
        new Main();
    }

}
public class Board extends JPanel{

    Explosion ex;

    public Board() 
    {           
        setDoubleBuffered(true); 

        ex = new Explosion(10,10);
        new Thread(ex).start();
    }

    public void paint(Graphics g) {
        ex.paintComponent(g);

        super.paint(g);
        Graphics2D g2d = (Graphics2D)g;
        Toolkit.getDefaultToolkit().sync();
        g.dispose();
    }
}

3 个答案:

答案 0 :(得分:3)

@StanislavL(我还不能发表评论):不,你不必在美国东部时间拨打repaint()

  

以下JComponent方法可以安全地从任何线程调用: repaint()revalidate()invalidate()repaint()revalidate()方法将请求事件派发线程的请求分别调用paint()validate()invalidate()方法只是将组件及其所有直接祖先标记为需要验证。

来源:http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html#exceptions

cursor是否被声明为volatile?如果没有,EDT可能看不到线程对cursor所做的更改。因此,始终会绘制第一张图像。

答案 1 :(得分:2)

  1. 请勿覆盖paint,而是覆盖paintComponent
  2. 请勿使用Thread.sleep,而是使用实用程序类(例如javax.swing.Timer)以指定的时间间隔执行特定操作。这将确保所有更改都在EDT上完成,并且等待发生在后台线程中。
  3. 请注意,如果没有可编译的代码,很难说出真正的问题是什么;这都是猜测。

答案 2 :(得分:1)

必须在EDT中调用重绘。

使用SwingUtilities.invokeAndWait()或invokeLater()来调用重绘。