Search code examples
javaperformanceswinggraphics2drepaint

Graphics2D painting getting too slow


I am developing an application that simulates Cellular Automatons. It happens that I need to draw really fast(each 100ms) a grid of 80x80 squares (6400 squares).

My first approach was using JLabels, but it was really slow. Now I am using Graphics2D and works great, but after drawing about 50 times, it starts getting slow, and goes getting slower as the turns advance.

I need to call repaint() after each turn in order to 'repaint' the squares, but I am guessing that what was drawn before is still in the memory, is that it? How can I discard what was draw so it will not ocupy the buffer ou memory?

A last thing, I saw this post but I can not see the difference between mine and the code provided there: post about repaint

Here's an image to help you understand what it's all about: Application running

And here is my code:

private void drawMatriz(int[][] array, DrawSquare square, int size, AppController contr) {
    Color[] configColors = contr.getArrayOfCollors();
    int posX = 0;
    int posY = 0;
    for (int i = 0; i < array.length; i++) {
        for (int j = 0; j < array[0].length; j++) {
            square.addSquare(posX, posY, size, size, configColors[array[i][j]]);
            posX += size;
        }
        posX = 0;
        posY += size;
    }
    repaint();
}

public AppRun(AppController controller) {
    [...]
    squares = new DrawSquare();
    squares.setBorder(new LineBorder(new Color(0, 0, 0)));
    squares.setBounds(209, 11, 640, 640);
    getContentPane().add(squares);
    squares.setPreferredSize(new Dimension(500, 500));
    squares.setLayout(null);

    drawMatriz(controller.getVector(), squares, (squares.getBounds().width / controller.getVector().length),
            controller);

}

class DrawSquare extends JPanel {
    private static final long serialVersionUID = 1L;
    private static final int PREF_W = 400;
    private static final int PREF_H = PREF_W;
    private List<Rectangle> squares = new ArrayList<Rectangle>();
    private List<Color> colors = new ArrayList<Color>();

    public void addSquare(int x, int y, int width, int height, Color color) {
        Rectangle rect = new Rectangle(x, y, width, height);
        squares.add(rect);
        colors.add(color);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(PREF_W, PREF_H);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        for (int i = 0; i < squares.size(); i++) {
            g2.setColor(colors.get(i));
            g2.fill(squares.get(i));
            g2.setColor(Color.BLACK);
            g2.draw(squares.get(i));
        }
    }
}

Solution

  • I don't see any problem with your paintComponent method.

    But you seem to never reset the contents of the ArrayLists in your DrawSquare class, for example by calling clear() on them. Hence, after the first call of drawMatriz(...) the ArrayLists have 6400 entries, after the second call they have 12800 entries, after 50 calls 320000 entries, ...