Java graphics - how to add delay between paint calls to create animation?

Chase Pareti :

I'm designing a simple fractal program in Java that will start by drawing a rectangle then recursively draw rectangles 1/4 the size at each corner. This will repeat and span in all directions until the dimensions converge to 0.

I have the program and design completely functional as of now; however, I'm making additions that I am unsure of how to do. When I run the program, the fractal is shown already complete in the JFrame that pops up. What I want to do is have each rectangle appear individually with a short delay between each one being painted.

I have a class for my main method which simply instantiates a GUI object and calls its run() method. For the most part, all the relevant code exists in these two files.

In the GUI class

public GUI()
 {
      Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
      fractal = new Fractal(this, screenSize.width, screenSize.height);

      this.setTitle("Fractals");
      this.setSize(screenSize.width, screenSize.height);
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      this.getContentPane().add(fractal);
      this.setFocusable(true);
      this.setVisible(true);
 }

 public void run()
 {
      fractal.repaint();
 }

In the Fractal class

public Fractal(GUI gui, int width, int height)
 {
      this.gui = gui;
      this.screenWidth = width;
      this.screenHeight = height;
 }

 @Override
 protected void paintComponent(Graphics g)
 {
      super.paintComponent(g);

      /* Calculate coordinates and dimensions */
      int x = 3 * this.screenWidth / 8;
      int y = 3 * this.screenHeight / 8;
      int width = this.screenWidth / 4;
      int height = this.screenHeight / 4;

      /* Draw the center rectangle */
      g.setColor(Color.BLACK);
      g.fillRect(x, y, width, height);

      /* Adjust dimensions for next rectangles */
      width /= 2;
      height /= 2;

      /* Draw rectangles at the corners */
      drawTopLeft(g, x - width, y - height, width, height);
      drawBottomLeft(g, x - width, y + (2 * height), width, height);
      drawTopRight(g, x + (2 * width), y - height, width, height);
      drawBottomRight(g, x + (2 * width), y + (2 * height), width, height);
 }

 public void drawTopLeft(Graphics g, int x, int y, int width, int height)
 {
      /* Ensure the boundaries lay within the screen */
      if(x > 0 && y > 0)
      {
           /* Draw itself */
           g.fillRect(x, y, width, height);

           /* Adjust dimensions for next rectangles */
           width /= 2;
           height /= 2;

           /* Draw rectangles at the corners */
           if(width > 0 && height > 0)
           {
                drawTopLeft(g, x - width, y - height, width, height);
                drawBottomLeft(g, x - width, y + (2 * height), width, height);
                drawTopRight(g, x + (2 * width), y - height, width, height);
           }
      }
 }

 public void drawBottomLeft(Graphics g, int x, int y, int width, int height)
 {
      /* Ensure the boundaries lay within the screen */
      if(x > 0 && y + height < screenHeight)
      {
           /* Draw itself */
           g.fillRect(x, y, width, height);

           /* Adjust dimensions for next rectangles */
           width /= 2;
           height /= 2;

           /* Draw rectangles at the corners */
           if(width > 0 && height > 0)
           {
                drawTopLeft(g, x - width, y - height, width, height);
                drawBottomLeft(g, x - width, y + (2 * height), width, height);
                drawBottomRight(g, x + (2 * width), y + (2 * height), width, height);
           }
      }
 }

 public void drawTopRight(Graphics g, int x, int y, int width, int height)
 {
      /* Ensure the boundaries lay within the screen */
      if(x + width < screenWidth && y > 0)
      {
           /* Draw itself */
           g.fillRect(x, y, width, height);

           /* Adjust dimensions for next rectangles */
           width /= 2;
           height /= 2;

           /* Draw rectangles at the corners */
           if(width > 0 && height > 0)
           {
                drawTopLeft(g, x - width, y - height, width, height);
                drawTopRight(g, x + (2 * width), y - height, width, height);
                drawBottomRight(g, x + (2 * width), y + (2 * height), width, height);
           }
      }
 }

 public void drawBottomRight(Graphics g, int x, int y, int width, int height)
 {
      /* Ensure the boundaries lay within the screen */
      if(x + width < screenWidth && y + height < screenHeight)
      {
           /* Draw itself */
           g.fillRect(x, y, width, height);

           /* Adjust dimensions for next rectangles */
           width /= 2;
           height /= 2;

           /* Draw rectangles at the corners */
           if(width > 0 && height > 0)
           {
                drawBottomLeft(g, x - width, y + (2 * height), width, height);
                drawTopRight(g, x + (2 * width), y - height, width, height);
                drawBottomRight(g, x + (2 * width), y + (2 * height), width, height);
           }
      }
 }

Here is what the output generates.

The fractal generation

WJS :

You need to calculate each rectangle outside of the paintComponent method. Each subsequent one should be stored in an array or list or some data structure. Then call repaint and sleep for 1 second (but don't sleep in the paintComponent method).

Your paintComponent method must then iterate thru the list of rectangles and paint each one. So each time repaint is called, your old ones and then your new one will be painted.

Bottom line, do not do much processing in paintComponent or any other method that runs in the EDT or your application will become unresponsive or not work as desired.

One more thing. Any drawing that you do in paintComponent will not be visible until you leave the method.

I didn't see you image earlier. If you are going to be drawing curves or diagonal lines, then set the following in paintComponent before painting. It will smooth out the graphics.

Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=157767&siteId=1