0

I am implementing a simple Canvas where items can be drawn like a person would in real life with a paper and a pencil, without clearing the entire page every time an object is drawn.

What I have so far...

A Canvas to implement the drawing:

public class Canvas extends JPanel {
    private final Random random = new Random();

    public Canvas() {
        setOpaque(false); // I thought setting this flag makes the drawn pixels be preserved...
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(640, 480);
    }

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

        g.drawOval(random.nextInt(getWidth()), random.nextInt(getHeight()), 5, 5);
    }
}

The Window as an actual window:

public class Window extends JFrame {
    public Window(Canvas canvas) {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        add(canvas);
        pack();
        setVisible(true);
    }
}

And the Controller with an entry-point to the application. Also starts a timer so the repaint on Canvas is called every second to force drawing another circle.

public class Controller {
    public static void main(String[] args) {
        Canvas canvas = new Canvas();
        SwingUtilities.invokeLater(() -> new Window(canvas));
        new Timer(1000, e -> canvas.repaint()).start();
    }
}

The problem is that whenever a new circle is drawn, the previous one is cleared. Seems like there is still some process filling the JPanel or maybe the entire JFrame with white color.

Snackoverflow
  • 5,332
  • 7
  • 39
  • 69

2 Answers2

1

Painting in Swing is destructive. It is an expected requirement that each time a component is painted, it is painted from scratch, again.

You need to define a model which maintains the information needed in order to restore the state from scratch.

Your paint routines would then iterate this model and draw the elements each time.

This has the benefit of allowing you to modify the model, removing or inserting elements, which would allow you to update what is been painted simply.

Alternatively, you could use a "buffer" (ie a BufferedImage) on to which all you painting is done, you would then simply paint the image to the component each time the component is painted.

This, however, means that you can't undo or layer the paintings, it's drawn directly to the image. It also makes resizing the drawing image area more difficult, as you need to make these updates manually, where as the "model" based implementation is far more adaptable

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I made it with `BufferedImage`, seems there is no other way to achieve this in a clean manner. – Snackoverflow Apr 01 '19 at 21:47
  • Personally, I'd go with a model, but I like it's flexibility, but you could technically use both, but needs drive musts ;) – MadProgrammer Apr 01 '19 at 21:48
  • My model is exactly that the information I need to preserve is the current state of an image. Everything else drawn must be drawn on top of everything existing. I never need to change the positions of anything existing, but there will be millions of components added and added... So the biggest amount of information I need can be stored in a single `BufferedImage`. – Snackoverflow Apr 01 '19 at 21:51
0

Consider calling the alternate constructor of repaint(...)

repaint(long tm, int x, int y, int width, int height)

This allows you to set a specified area to be repainted.

Also you can just store what you drew in a list and then reprint the drawing to the canvas after repaint is called.

Julian Peffer
  • 307
  • 1
  • 4
  • Unfortunately for this task I will have the list contain millions of elements drawn over a long period of time (several minutes). The specified area to be repainted will always be none, as I want the entire `Canvas` to be preserved through-out the life of the application. Only a manual *clear* should fill the canvas. – Snackoverflow Apr 01 '19 at 21:39
  • 1
    This thread seems like it could help you alot. https://stackoverflow.com/questions/15621313/repaint-without-clearing – Julian Peffer Apr 01 '19 at 21:45
  • Yes, actually I was looking for existing answers but couldn't find it before. – Snackoverflow Apr 01 '19 at 21:48