Min Fan
Min Fan

Reputation: 1

java gui paintComponent refresh

I am learning java gui interface and wrote a program that has a button. Each time the button is clicked, a random sized rectangle will be added to the screen. But instead of adding it to the screen, the program keeps erasing the old one, which I want to keep on the screen. Here is my code. I tried to do paint() and it did not work. Thanks in advance.

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

public class SimpleGui implements ActionListener {
JFrame frame =  new JFrame();
public static void main(String[] args){
    SimpleGui gui = new SimpleGui();
    gui.go();
}

public void go(){
    JButton button = new JButton("Add a rectangle");
    MyDrawPanel panel = new MyDrawPanel();

    button.addActionListener(this);

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(BorderLayout.SOUTH, button);
    frame.getContentPane().add(BorderLayout.CENTER, panel);

    frame.setSize(300, 300);
    frame.setVisible(true);
}

public void actionPerformed(ActionEvent event){
    frame.repaint();
}
class MyDrawPanel extends JPanel{
    public void paintComponent(Graphics g){
        g.setColor(Color.blue);

        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);
        g.fillRect(x, y, height, width);

    }
}
}

Upvotes: 0

Views: 1500

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

Your paintComponent method is written to draw only one rectangle, so its behavior should come as no shock to you. If you want it to draw multiple, you have one of two options:

  • Create an ArrayList<Rectangle>, and in the actionPerformed method, add a new random Rectangle to this List and then call repaint(). In the paintComponent method, iterate through this List with a for-loop, painting each Rectangle.
  • Or you could draw the new random rectangle onto a BufferedImage that is displayed by the paintComponent method.

The first method is the easier of the two, the 2nd is better if you're worried about program responsiveness, say in an animation program.

For example:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.*;

@SuppressWarnings("serial")
public class TwoDrawRectMethods extends JPanel {
    // Array to hold our two drawing JPanels
    private AddRandomRect[] addRandomRects = {
            new DrawList("Using List"), 
            new DrawBufferedImage("Using BufferedImage")};

    // constructor
    public TwoDrawRectMethods() {
        // add drawing rectangles onto GUI
        for (AddRandomRect addRandomRect : addRandomRects) {
            add(addRandomRect);
        }
        // button to tell rectangles to add a new Rectangle
        add(new JButton(new DrawAction("Add New Rectangle")));
    }

    // The button's Action -- an ActionListener on "steroids"
    private class DrawAction extends AbstractAction {
        public DrawAction(String name) {
            super(name);
            int mnemonic = (int) name.charAt(0);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // tell both drawing JPanels to add a new rectangle
            for (AddRandomRect addRandomRect : addRandomRects) {
                addRandomRect.addRectangle();
            }
        }
    }

    private static void createAndShowGui() {
        TwoDrawRectMethods mainPanel = new TwoDrawRectMethods();

        JFrame frame = new JFrame("TwoDrawRectMethods");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

@SuppressWarnings("serial")
class DrawList extends AddRandomRect {
    private static final Color RECT_COLOR = Color.RED;
    private List<Rectangle> rectList = new ArrayList<>();

    public DrawList(String title) {
        super(title);
    }

    @Override
    public void addRectangle() {
        rectList.add(createRandomRect());
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(RECT_COLOR);
        for (Rectangle rectangle : rectList) {
            g2.draw(rectangle);
        }
    }


}

@SuppressWarnings("serial")
class DrawBufferedImage extends AddRandomRect {
    private static final Color RECT_COLOR = Color.BLUE;
    private BufferedImage img = null;

    public DrawBufferedImage(String title) {
        super(title);
    }

    @Override
    public void addRectangle() {
        if (img == null) {
            img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
        }
        Rectangle rect = createRandomRect();
        Graphics2D g2 = img.createGraphics();
        g2.setColor(RECT_COLOR);
        g2.draw(rect);
        g2.dispose();
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (img != null) {
            g.drawImage(img, 0, 0, null);
        }
    }

}

@SuppressWarnings("serial")
abstract class AddRandomRect extends JPanel {
    private static final int PREF_W = 500;
    private static final int PREF_H = PREF_W;
    private Random random = new Random();

    public AddRandomRect(String title) {
        setBorder(BorderFactory.createTitledBorder(title));
    }

    abstract void addRectangle();

    protected Rectangle createRandomRect() {
        int x1 = random.nextInt(PREF_W);
        int x2 = random.nextInt(PREF_W);
        int y1 = random.nextInt(PREF_H);
        int y2 = random.nextInt(PREF_H);

        int x = Math.min(x1, x2);
        int y = Math.min(y1, y2);
        int width = Math.abs(x1 - x2);
        int height = Math.abs(y1 - y2);
        return new Rectangle(x, y, width, height);        
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }
}

Upvotes: 3

Related Questions