0

I am trying to draw an image on a JPanel that requires thousands of calculations, and I want to animate the progression of the drawing. I.e., instead of doing all 100K iterations of drawing in one go, and then repainting the JPanel, I want to repaint after each iteration, then pause for a fraction of a second, so the user sees the image gradually appearing. However, each refresh of the JPanel erases previous drawings, so my method doesn't work. How can I do this without replicating all (1..N-1) calculations on the Nth iteration?

Consider this example: I want "snow" to gradually appear on the screen. However, this code will only show the 100,000th "snowflake" as all previous ones get erased each time repaint() is called.

import javax.swing.*;
import java.awt.*;
import java.util.Random;

class spanel extends JPanel{    
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawLine(snow.x, snow.y, snow.x, snow.y);
    }
}

class snow extends Thread {

    static int x,y;
    Random r = new Random();

    public void run(){

        JFrame sboard = new JFrame();
        sboard.setSize(600,600);
        sboard.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        spanel mypanel = new spanel();
        sboard.add(mypanel);
        sboard.setVisible(true);

        for (int i=0;i<100000;i++){
            x=r.nextInt(600);
            y=r.nextInt(600);

            sboard.repaint();    
            try {
                snow.sleep((long)10);
            } catch (InterruptedException e) {}; 
        } 
    }
}

public class SnowAnim {    
    public static void main(String[] args) {
        (new snow()).start();
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
Andrei Utkin
  • 71
  • 1
  • 1
  • 3

4 Answers4

1

Custom Painting Approaches shows how to draw on a BufferedImage. There are also plenty of other examples in the forum.

Also, when doing animation you should use a Swing Timer to schedule the animation.

camickr
  • 321,443
  • 19
  • 166
  • 288
1

How can I do this without replicating all (1..N-1) calculations on the Nth iteration?

Add them to a BufferedImage as seen in this example.

Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
0

You should probably do your painting on a buffer, then draw the current state of the buffer in paintComponent();

You could also skip the call to super.paintComponent(g);, but then you would have to worry about other elements getting visually "stuck" in your panel.

Sam Dufel
  • 17,560
  • 3
  • 48
  • 51
  • Thanks. I tried skipping super.paintComponent, but it didn't help for whatever reason. Can you please point me to examples of drawing on a buffer (I assume you mean BufferedImage?) and how to copy it back? – Andrei Utkin Apr 12 '13 at 23:36
  • See http://stackoverflow.com/questions/10628492/dynamic-graphics-object-painting-in-java/10628553#10628553, as pointed out by Andrew – Sam Dufel Apr 13 '13 at 01:49
0

Thanks all! I figured it out. BufferedImage solves it. For the record, here is my updated code. It also implements camickr's suggestion to use a Swing timer instead of a thread to schedule the animation. I also made some aesthetic changes to make the output look more like snow :-) Thanks again!

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.util.Random;
import java.awt.event.*;

class spanel extends JPanel{
    int x,y,rad,i;
    static Random r = new Random();
    BufferedImage image;
    Graphics2D g2d;
    Timer timer;

    spanel(){
        image = new BufferedImage(600, 600, BufferedImage.TYPE_INT_ARGB);
        g2d = (Graphics2D)image.getGraphics();
        setBackground(Color.black);
        g2d.setColor(Color.white);
        i=0;
        ActionListener listener = new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                iterate();
            }
        };
        timer = new Timer(10, listener);
        timer.start();
    }
    public void iterate(){
        x=r.nextInt(600);
        y=r.nextInt(600);
        rad=r.nextInt(5)+5;
        g2d.fillOval(x, y, rad, rad);
        repaint();    
        i++;
        if (i==1000){timer.stop();}
    }
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(image,0,0,null);
        }
    }


public class SnowAnim {    
    public static void main(String[] args) {
        JFrame sboard = new JFrame();
        sboard.setSize(600,600);
        sboard.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        spanel mypanel = new spanel();
        sboard.add(mypanel);
        sboard.setVisible(true);
    }
}
Andrei Utkin
  • 71
  • 1
  • 1
  • 3