Search code examples
javaswingcustom-painting

Trouble with repainting the screen, but not clearing previous shapes


I am working on simulation of the chaos game for the sierpinski triangle.

I'm trying to paint a new point, without clearing the last one. As the number of points increases on the GUI to create the sierpinski triangle image, the speed in which points are plotted, decreases because of the for loop. I want to run this program without a for loop, but every time I repaint, the previous point clears.

As of now, I have a working version of this program that I made, but I want it to be more efficient.

Here's my code for the whole program.

import javax.swing.*; //JFrame and JPanel
import java.awt.*; //Color and Container
import javax.swing.JOptionPane;
import java.awt.event.*;
import java.util.Scanner;
import java.io.*;
import java.util.Random;
import java.util.ArrayList;
import java.util.List;

/**
 * Write a description of class ChaosGame here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class ChaosGame
{
    public static void main(String[] args) {
        JFrame theGUI = new JFrame("Chaos Game");
        theGUI.setSize(800, 800);
        theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ColorPanel panel = new ColorPanel(Color.white);
        Container pane = theGUI.getContentPane();
        pane.add(panel);
        theGUI.setVisible(true);
    }
}
class ColorPanel extends JPanel implements MouseMotionListener, MouseListener{
    private Random random = new Random();
    private Seed s;
    private Red r;
    private Blue b;
    private Green gr;
    private boolean followMouse = true;
    javax.swing.Timer timer;
    javax.swing.Timer arraytimer;
    private int x, y;
    private int newx, newy;
    private int redx = 100;
    private int redy = 660;
    private int bluex = 700;
    private int bluey = 660;
    private int greenx = 400;
    private int greeny = 140;
    private int pointx, pointy;
    private int seedx, seedy;
    private int i;
    private int dotcounter;
    private Point[] p = new Point[10000];

    public ColorPanel(Color backcolor){
        setBackground(backcolor);
        s = new Seed(400, 400, Color.YELLOW);
        r = new Red(100, 660, Color.RED);
        b = new Blue(700, 660, Color.BLUE);
        gr = new Green(400, 140, Color.GREEN);
        i = 0;
        dotcounter = 0;
        addMouseListener(this);
        addMouseMotionListener(this);
        this.setFocusable(true);
        timer = new javax.swing.Timer(1, new MoveListener());
        arraytimer = new javax.swing.Timer(1, new ArrayTimer());
    }

    public void paintComponent(Graphics g){
        //tells ball what to do when it hits the sides
        super.paintComponent(g);
        r.fill(g);
        b.fill(g);
        gr.fill(g);
        s.fill(g);
        Font font = new Font("Courier", Font.PLAIN, 30);
        g.setFont(font);

        if (followMouse == true){
            timer.start();
            s.moveto(x, y);
            g.drawString("Seed" ,x + 10, y - 10);
        }
        else if (followMouse == false){
            timer.stop();
            arraytimer.start();
            s.moveto(seedx, seedy);
            int n = random.nextInt(3) + 1;
            newx = pointx;
            newy = pointy;
            //1 = red
            //2 = green
            //3 = blue
            if(dotcounter <= 14){
                if (n == 1){
                    pointx = (newx + redx) / 2;
                    pointy = (newy + redy) / 2;
                    p[dotcounter] = new Point(pointx, pointy, Color.WHITE);
                }
                else if (n == 2){
                    pointx = (newx + greenx) / 2;
                    pointy = (newy + greeny) / 2;
                    p[dotcounter] = new Point(pointx, pointy, Color.WHITE);
                }
                else if (n == 3){
                    pointx = (newx + bluex) / 2;
                    pointy = (newy + bluey) / 2;
                    p[dotcounter] = new Point(pointx, pointy, Color.WHITE);
                }
            }
            else if (dotcounter >= 15 && dotcounter < 10000){
                if (n == 1){
                    pointx = (newx + redx) / 2;
                    pointy = (newy + redy) / 2;
                    p[dotcounter] = new Point(pointx, pointy, Color.RED);
                }
                else if (n == 2){
                    pointx = (newx + greenx) / 2;
                    pointy = (newy + greeny) / 2;
                    p[dotcounter] = new Point(pointx, pointy, Color.GREEN);
                }
                else if (n == 3){
                    pointx = (newx + bluex) / 2;
                    pointy = (newy + bluey) / 2;
                    p[dotcounter] = new Point(pointx, pointy, Color.BLUE);
                }
            }
            else{
                arraytimer.stop();
            }
            for (i = 0; i < dotcounter; i++)
            { 
                p[i].fill(g);
            }
        }
        g.drawString(""+dotcounter, 600, 60);
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // TODO Auto-generated method stub
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        x = e.getX();
        y = e.getY();
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        // TODO Auto-generated method stub
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        // TODO Auto-generated method stub
    }

    @Override
    public void mouseExited(MouseEvent e) {
        // TODO Auto-generated method stub
    }

    @Override
    public void mousePressed(MouseEvent e){
        if (followMouse == true){
            seedx = x;
            seedy = y;
            pointx = seedx;
            pointy = seedy;
            followMouse = false;
        }
        else{}
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub
    }

    private class MoveListener implements ActionListener{
        public void actionPerformed(ActionEvent e){
            repaint();
        }
    }
    private class ArrayTimer implements ActionListener{
        public void actionPerformed(ActionEvent e){
            dotcounter++;
            repaint();
        }
    }
}
class Seed{
    private int centerX, centerY, radius;
    private Color color;
    public Seed(int x, int y, Color thecolor){
        centerX = x;
        centerY = y;
        radius = 4;
        color = thecolor;
    }

    public void fill(Graphics g){
        //fills circle
        Color oldColor = g.getColor();
        g.setColor(color);
        g.fillOval(centerX-radius, centerY-radius, radius*2, radius*2);
        g.setColor(oldColor);
    }

    public void moveto(int xAmount, int yAmount){
        //Moves ball
        centerX = xAmount;
        centerY = yAmount;
    }
}
class Red{
    private int centerX, centerY, radius;
    private Color color;
    public Red(int x, int y, Color thecolor){
        centerX = x;
        centerY = y;
        radius = 4;
        color = thecolor;
    }

    public void fill(Graphics g){
        //fills circle
        Color oldColor = g.getColor();
        g.setColor(color);
        g.fillOval(centerX-radius, centerY-radius, radius*2, radius*2);
        g.setColor(oldColor);
    }

    public void moveto(int xAmount, int yAmount){
        //Moves ball
        centerX = xAmount;
        centerY = yAmount;
    }
}
class Blue{
    private int centerX, centerY, radius;
    private Color color;
    public Blue(int x, int y, Color thecolor){
        centerX = x;
        centerY = y;
        radius = 4;
        color = thecolor;
    }

    public void fill(Graphics g){
        //fills circle
        Color oldColor = g.getColor();
        g.setColor(color);
        g.fillOval(centerX-radius, centerY-radius, radius*2, radius*2);
        g.setColor(oldColor);
    }

    public void moveto(int xAmount, int yAmount){
        //Moves ball
        centerX = xAmount;
        centerY = yAmount;
    }
}
class Green{
    private int centerX, centerY, radius;
    private Color color;
    public Green(int x, int y, Color thecolor){
        centerX = x;
        centerY = y;
        radius = 4;
        color = thecolor;
    }

    public void fill(Graphics g){
        //fills circle
        Color oldColor = g.getColor();
        g.setColor(color);
        g.fillOval(centerX-radius, centerY-radius, radius*2, radius*2);
        g.setColor(oldColor);
    }

    public void moveto(int xAmount, int yAmount){
        //Moves ball
        centerX = xAmount;
        centerY = yAmount;
    }
}
class Point{
    private int centerX, centerY, radius;
    private Color color;
    public Point(int x, int y, Color thecolor){
        centerX = x;
        centerY = y;
        radius = 1;
        color = thecolor;
    }

    public void fill(Graphics g){
        //fills circle
        Color oldColor = g.getColor();
        g.setColor(color);
        g.fillRect(centerX-radius, centerY-radius, radius, radius);
        g.setColor(oldColor);
    }

    public void moveto(int xAmount, int yAmount){
        //Moves ball
        centerX = xAmount;
        centerY = yAmount;
    }
}

Solution

  • Check out Custom Painting Approaches for the two common ways to do this:

    1. Keep a List of Object to paint and iterate through this list every time the component needs to be repainted
    2. Draw onto a BufferedImage and then just repaint the image.

    Sounds like the second approach is what you need if you have a performance problem with the first approach.