CodingBoy
CodingBoy

Reputation: 1

Using the repaint() method in a JPanel without erasing what is already drawn

I originally made the program as follows. I used extends Canvas and the update method to continually draw more points. My understanding is that every time repaint() is called the new points are added onto the existing Canvas through the use of the update() method. If the method was paint() instead of update() every time repaint() was called it would paint a new Canvas with only fifty points. This is my BarnsleyFern class which extends Canvas.

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Canvas;
import java.lang.Math;
import java.awt.event.*;
import javax.swing.*;
public class BarnsleyFern extends Canvas
{
   private double newX,x=0;
   private double newY,y=0;
   public BarnsleyFern(int width, int height)
   {
      setBackground(Color.BLACK);
      setSize(width,height);
      setVisible(true);
      ActionListener action = new ActionListener()
      {
         public void actionPerformed(ActionEvent event)
         {  
            repaint();
         }
      };
      Timer timer = new Timer(100,action);
      timer.start();
   }
   public void update(Graphics window)
   {
      Graphics2D g2d = (Graphics2D)window;
      window.translate(360,800);
      //g2d.rotate(Math.toRadians(180));
      fern(window);
   }
   public void fern(Graphics window)
   {
      Color newColor = new Color((int)(Math.random()*256),(int)(Math.random()*256),(int)(Math.random()*256));
      for(int i=0;i<50;i++)
      {
         window.setColor(Color.BLUE);
         int rand = (int)(Math.random()*100);
         if(rand<1)
         {
            newX=0;
            newY=0.16*y;
         }
         else if(rand<86)
         {
            newX=0.85*x + 0.04*y;
            newY=0.85*y - 0.04*x + 1.6;
         }  
         else if(rand<93)
         {
            newX=0.20*x - 0.26*y;
            newY=0.23*x + 0.22*y + 1.6;
         }
         else
         {
            newX=0.28*y - 0.15*x;
            newY=0.26*x + 0.24*y + 0.44;
         }
         window.fillOval((int)(newX*165.364),-(int)(newY*80.014),2,2);   
         x=newX;
         y=newY;
      }
   }
}

The following code is the BarnsleyFernRunner class which extends JFrame. This sets up the JFrame and contains the main method.

import javax.swing.JFrame;
public class BarnsleyFernRunner extends JFrame
{
   public BarnsleyFernRunner()
   {
      setTitle("Barnsley Fern");
      setSize(800,800);
      add(new BarnsleyFern(800,800));
      setVisible(true);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   }
   public static void main(String[] args)
   {  
      BarnsleyFernRunner runner = new BarnsleyFernRunner();
   }
}

I then decided to change my code a little by extending JPanel instead of extending Canvas. I choose to do this because the JPanel and JFrame are both from the javax.swing package. The new BarnsleyFern class uses the BarsnleyFernRunner class from above. This class does not work the same way as it did before. Each time repaint() is called fifty new points are draw and the old ones disappear. My understanding is that this is the case because every time repaint() is called a new JPanel is made. My question is how can I call the repaint() method within the JPanel without creating a whole new JPanel. Is there a way to call repaint() without "erasing" what I already have drawn. Is there a way I can duplicate what I did in the first class with the update() method. This is my BarnsleyFern class which extends JPanel

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.Canvas;
import java.lang.Math;
import java.awt.event.*;
import javax.swing.*;
public class BarnsleyFern extends JPanel
{
   private double newX,x=0;
   private double newY,y=0;
   public BarnsleyFern(int width, int height)
   {
      setBackground(Color.BLACK);
      setSize(width,height);
      setVisible(true);
      ActionListener action = new ActionListener()
      {
         public void actionPerformed(ActionEvent event)
         {  
            repaint();
         }
      };
      Timer timer = new Timer(100,action);
      timer.start();
   }
   public void paintComponent(Graphics window)
   {
      super.paintComponent(window);
      Graphics2D g2d = (Graphics2D)window;
      window.translate(360,800);
      //g2d.rotate(Math.toRadians(180));
      fern(window);
   }
   public void fern(Graphics window)
   {
      Color newColor = new Color((int)(Math.random()*256),(int)(Math.random()*256),(int)(Math.random()*256));
      for(int i=0;i<50;i++)
      {
         window.setColor(Color.BLUE);
         int rand = (int)(Math.random()*100);
         if(rand<1)
         {
            newX=0;
            newY=0.16*y;
         }
         else if(rand<86)
         {
            newX=0.85*x + 0.04*y;
            newY=0.85*y - 0.04*x + 1.6;
         }  
         else if(rand<93)
         {
            newX=0.20*x - 0.26*y;
            newY=0.23*x + 0.22*y + 1.6;
         }
         else
         {
            newX=0.28*y - 0.15*x;
            newY=0.26*x + 0.24*y + 0.44;
         }
         window.fillOval((int)(newX*165.364),-(int)(newY*80.014),2,2);   
         x=newX;
         y=newY;
      }
   }
}

Upvotes: 0

Views: 879

Answers (1)

Mad Physicist
Mad Physicist

Reputation: 114230

When you call super.paintComponent(window); in your paintComponent() method, you are asking JPanel to paint your border and background. Painting a background means clobbering whatever was there before.

The simplest way to deal with this is to simply omit the call to super.paintComponent(window);. Another way is to call setOpaque(false);. This tells the panel that you are responsible for drawing the background yourself.

Upvotes: 0

Related Questions