Drawing on JPanel step by step

I would like to create a JPanel and draw things on it one by one. I would like to see them added after each other. The problem is, I always have to wait until everything is finished by paintComponent method. Is there a way to achieve what I desire? Thanks in advance!

package javapaintui;

import java.awt.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

class JavaPaintUI extends JFrame {

    private JPanel jPanel2;

    public JavaPaintUI() {
        initComponents();
    }

    private void initComponents() {
        jPanel2 = new Panel2();
        this.setContentPane(jPanel2);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
    }

    class Panel2 extends JPanel {

        Panel2() {
            setPreferredSize(new Dimension(420, 420));
        }

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

            g.drawString("BLAH", 20, 20);
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {
                Logger.getLogger(JavaPaintUI.class.getName()).log(Level.SEVERE, null, ex);
            }
            g.drawRect(200, 200, 200, 200);
        }
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new JavaPaintUI().setVisible(true);
            }
        });
    }
}

Answers


Never, ever, ever use Thread.sleep(...) in a Swing application's event dispatch thread. That goes 100-fold true for the paintComponent method as you put it to sleep. The solution is to use a Swing Timer.

e.g.,

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.*;

class JavaPaintUI extends JFrame {
   private static final Color FILL_COLOR = Color.BLUE;
   private static final Color BORDER_COLOR = Color.RED;
   public static final Stroke STROKE = new BasicStroke(4f);

   private JPanel jPanel2;

   public JavaPaintUI() {
      initComponents();
   }

   private void initComponents() {
      jPanel2 = new Panel2();
      this.setContentPane(jPanel2);
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();
   }

   class Panel2 extends JPanel {
      private static final int TIMER_DELAY = 2000;
      private Random random = new Random();
      private List<Shape> shapeList = new ArrayList<>();

      Panel2() {
         setPreferredSize(new Dimension(420, 420));
         new Timer(TIMER_DELAY, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent evt) {
               int width = random.nextInt(100);
               int height = random.nextInt(100);
               int x = random.nextInt(getWidth() - width);
               int y = random.nextInt(getHeight() - height);
               shapeList.add(new Rectangle(x, y, width, height));
               repaint();
            }
         }).start();
      }

      @Override
      public void paintComponent(Graphics g) {
         super.paintComponent(g);
         g.drawString("BLAH", 20, 20);
         Graphics2D g2 = (Graphics2D) g;
         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
               RenderingHints.VALUE_ANTIALIAS_ON);
         g2.setStroke(STROKE);
         for (Shape shape : shapeList) {
            g2.setColor(FILL_COLOR);
            g2.fill(shape);
            g2.setColor(BORDER_COLOR);
            g2.draw(shape);
         }
      }
   }

   public static void main(String args[]) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            new JavaPaintUI().setVisible(true);
         }
      });
   }
}

Edit You ask:

Now the problem is, I intend to draw a binary tree. The drawing mechanism works this way: I pass the tree's root to the drawing function, which will iterate through it, and draw a tree on the panel. I use drawString, drawOval and drawLine functions, which seems to be hard to implement this way. Do you have a solution for it maybe?

Actually I've given you the perfect solution for this. The shapeList List<Shape> variable will accept anything that implements the Shape interface which means you can add Line2D, Ellipse2D and similar objects as well as text to it.


Need Your Help

Json object with backslash, gson serialization

json gson

I want to convert a java object to json object with string format*. I am using gson library. Is there any way to do that.