简体   繁体   English

重新绘制JPanel

[英]Repaint a JPanel

I would like to repaint my jPanel I've a App class who handle the screen displaying in this JFrame I add a Board JPanel object who handle all the JPanel. 我想重绘我的jPanel,我有一个App类负责处理此JFrame中显示的屏幕,我添加了一个处理所有JPanel的Board JPanel对象。 In the Board class I had 在董事会班上

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

And in my Explosion class I have a constructor who crop my sprite file, an overwriting of paint() and : 在Explosion类中,我有一个构造函数,该构造函数裁剪了我的sprite文件,覆盖了paint()和:

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

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

            System.out.println(cursor);

            cursor++;
        }
    }

The loop is working fine but I have no repaint in my screen , only the first image is display. 循环工作正常,但屏幕上没有重画,仅显示第一个图像。

What can I do to refresh ? 我该怎么做才能刷新?

Thanks 谢谢

Edit : Here is my code : 编辑:这是我的代码:

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();
    }
}

@StanislavL (I can't comment yet): No, you don't have to call repaint() in the EDT: @StanislavL(我无法评论):不,您不必在EDT中调用repaint()

The following JComponent methods are safe to call from any thread: repaint() , revalidate() , and invalidate() . 可以从任何线程安全调用以下JComponent方法: repaint()revalidate()invalidate() The repaint() and revalidate() methods queue requests for the event-dispatching thread to call paint() and validate() , respectively. repaint()revalidate()方法将事件调度线程的请求排队,以分别调用paint()validate() The invalidate() method just marks a component and all of its direct ancestors as requiring validation. invalidate()方法仅将组件及其所有直接祖先标记为需要验证。

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

Is cursor declared as volatile ? cursor是否声明为volatile If not, the EDT may not see the changes the thread made to cursor . 如果不是,则EDT可能看不到线程对cursor所做的更改。 Therefore, always the first image is painted. 因此,始终绘制第一张图像。

  1. Do not override paint , instead override paintComponent 不要覆盖paint ,而是覆盖paintComponent
  2. Do not use Thread.sleep , instead use a utility class, such as javax.swing.Timer to execute a particular action at a specified interval. 不要使用Thread.sleep ,而要使用实用程序类,例如javax.swing.Timer ,以指定的时间间隔执行特定的操作。 This will ensure that all changes are done on the EDT and that the waiting occurs in a background thread. 这将确保所有更改都在EDT上完成,并且等待发生在后台线程中。

Note that without compilable code, it's hard to tell what the real problem is; 注意,没有可编译的代码,很难说出真正的问题是什么; this is all guesswork. 这都是猜测。

Repaint must be called in EDT. 必须在EDT中调用重绘。

Use SwingUtilities.invokeAndWait() or invokeLater() to call repaint. 使用SwingUtilities.invokeAndWait()或invokeLater()调用重绘。

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

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