1

What code should I add so that the rectangles painted before continue to exist on the screen when new ones are printed.Here is the code

import javax.sound.midi.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;


public class MiniMusicPlayer3 
{
    private boolean fire = false;
    private JFrame frame;

    public static void main(String args[])
    {
        MiniMusicPlayer3 mini = new MiniMusicPlayer3();
        mini.go();
    }
    public void go()
    {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(600,600);
        frame.setVisible(true);
        MyDrawPanel boxes = new MyDrawPanel();
        frame.getContentPane().add(boxes);
        try
        {
            Sequencer player =MidiSystem.getSequencer();
            player.open();

            Sequence seq = new Sequence(Sequence.PPQ,4);
            Track track = seq.createTrack();

            int arr[] ={127};
            player.addControllerEventListener(new MyDrawPanel(),arr);

            //add notes to the track
            for(int i = 5;i<61;i+=4)
            {
                track.add(makeEvent(144,1,i,100,i));
                track.add(makeEvent(176,1,127,0,i));
                track.add(makeEvent(128,1,i,100,(i+2)));
            }

            player.setSequence(seq);
            player.setTempoInBPM(220);
            player.start();
        }
        catch(Exception ex)
        {

        }
    }

    public MidiEvent makeEvent(int onOff,int one,int note,int vel,int tick)
    {
        MidiEvent event = null;
        try
        {
            ShortMessage a = new ShortMessage();
            a.setMessage(onOff,one,note,vel);
            event = new MidiEvent(a,tick);
        }
        catch(Exception e)
        {

        }
        finally
        {
            return event;
        }
    }

    class MyDrawPanel extends JPanel implements ControllerEventListener
    {

        public void controlChange(ShortMessage message)
        {
            System.out.println("control change happens");
            fire = true;
            frame.repaint();
        }

        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            if(fire)
            {
            Graphics2D g2d = (Graphics2D)g;
            int red = (int)(Math.random()*255);
            int blue = (int)(Math.random()*255);
            int green = (int)(Math.random()*255);

            Color color = new Color(red,blue,green);
            g2d.setColor(color);

            int height = (int)((Math.random()*120)+10);
            int width = (int)((Math.random()*120)+10);

            int x = (int)((Math.random()*40)+10);
            int y = (int)((Math.random()*40)+10);

            g2d.fillRect(x, y, width, height);
            fire = false;
            }
        }
    }
}

Also why does the code above not let the rectangles persist as opposed to the code below that allows the circles to persist

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class Animate 
{
    private JFrame frame;
    private int x=10,y=10;
    public static void main(String args[])
    {
        Animate ballRoll = new Animate();
        ballRoll.go();
    }

    public void go()
    {
        frame = new JFrame();
        frame.setSize(500,500);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        MyRoll ball = new MyRoll();
        frame.getContentPane().add(ball);
        for(x = 5;x<=350;x++)
        {
            y=x;

            try
            {
                Thread.sleep(50);
            }
            catch(Exception e)
            {
                System.out.println("dsfsd");
            }
            ball.repaint();
        }


    }

    class MyRoll extends JPanel
    {
        public void paintComponent(Graphics g)
        {
            g.setColor(Color.ORANGE);
            g.fillOval(x, y, 100, 100);
        }
    }
}
user3760100
  • 679
  • 1
  • 9
  • 20

4 Answers4

3

Replace frame.repaint() with this.repaint() and remove super.paintComponent(g) if you want to persist the previous painting as well but I never suggest you to use this approach. You have to redraw all the objects again in paintComponent().

Please have a look at below sections for detail information about Paint processing in Swing application.

Braj
  • 46,415
  • 5
  • 60
  • 76
3

"What code should I add so that the rectangles previously printed persist,instead of getting erased when the new rectangles are painted?"

  • Create a list of Rectangle2D object (as a class member).
  • Loop through the list in the paintComponent and paint each rectangle.
  • When you want to add a new rectangle, well, add a new rectangle to the list and repaint.
  • If you want different colors (or and other state) for each rectangle, create a wrapper like (See some of the examples below).

"Also why does the code above not let the rectangles persist as opposed to the code below that allows the circles to persist"

No rectangle are not "persisting" per se. What you are seeing are paint artifacts from not calling super.paintComponent which clears the previous paint. You should always call super.paintComponent though, like in your first example. So your best options is to go with the first part of my answer.

See a bunch of examples here and here and here and here and here and here.

The basic premise of all those examples is storing a list of similar object in a list and iterating through the list to paint all the objects. Each object can have its own specific state.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • You should always call `super.paintComponent` *unless you are filling the entire canvas yourself*. – Fabian Jun 21 '14 at 13:00
2

You could also extend your MyDrawPanel class so you keep track of which rectangles to paint plus their colors. So you could add each new rectangle to a list of rectangles and keep track of the rectangle colors using a map. Then you just need to add new rectangles to the list and the new color to the map. Finally, you'll need to loop through the list of rectangles and paint these one by one.

Here is how it could be done:

class MyDrawPanel extends JPanel implements ControllerEventListener
{
    // List of all rectangles that needs to be painted
    java.util.List<Rectangle> rectangles = new ArrayList<Rectangle>();
    // Map over all colors for each rectangle that must be painted
    Map<Rectangle, Color> rectangleColors = new HashMap<Rectangle, Color>();

    public void controlChange(ShortMessage message)
    {
        System.out.println("control change happens");
        fire = true;
        frame.repaint();
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        if(fire)
        {
        Graphics2D g2d = (Graphics2D)g;
        int red = (int)(Math.random()*255);
        int blue = (int)(Math.random()*255);
        int green = (int)(Math.random()*255);

        Color color = new Color(red,blue,green);
        g2d.setColor(color);

        int height = (int)((Math.random()*120)+10);
        int width = (int)((Math.random()*120)+10);

        int x = (int)((Math.random()*40)+10);
        int y = (int)((Math.random()*40)+10);

        // Create a new rectangle to paint
        Rectangle newRect = new Rectangle(x, y, width, height);
        // Store the rectangle in the list over rectangles to paint
        rectangles.add(newRect);
        // Add the color of the rectangle in the map over rectangle colors
        rectangleColors.put(newRect, color);

        // Paint all the rectangles using their colors one by one
        for (Rectangle rect : rectangles) {
            // Get the color of the rectangle
            Color rectColor = rectangleColors.get(rect);
            // Set the rectangle color
            g2d.setColor(rectColor);
            // Fill the rectangle with the rectangle color
            g2d.fill(rect); 
        }
        fire = false;
        }
    }
}
FNL
  • 133
  • 1
  • 8
1

There are two common approaches:

  1. as has already been mentioned a couple of times, you keep a List of objects to paint and then iterate through the List in the paintComponent(...) method.

  2. draw to a BufferedImage.

Take a look at Custom Painting Approaches which exams both of these approaches and contains working examples of both.

camickr
  • 321,443
  • 19
  • 166
  • 288