Graphics2D绘画变得太慢了

时间:2017-03-10 19:08:11

标签: java performance swing graphics2d repaint

我正在开发一个模拟元胞自动机的应用程序。碰巧我需要画得非常快(每100毫秒)一个80x80正方形(6400格)的网格。

我的第一种方法是使用JLabels,但它确实很慢。现在我使用的是Graphics2D并且效果很好,但是在绘制了大约50次后,它开始变慢,并且随着转弯的进行而变慢。

我需要在每次转弯后调用repaint()以“重新绘制”方块,但我猜测之前绘制的内容仍然在内存中,是吗?我如何丢弃所绘制的内容,这样它就不会使缓冲区内存发生?

最后一件事,我看到这篇文章,但我看不出我和那里提供的代码之间的区别:post about repaint

这是一张图片,可以帮助您了解它的全部内容: Application running

这是我的代码:

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));
        }
    }
}

2 个答案:

答案 0 :(得分:2)

我的paintComponent方法没有任何问题。

但您似乎永远不会重置ArrayList课程中DrawSquare的内容, 例如,通过调用clear()。 因此,在第一次调用drawMatriz(...)之后ArrayList有6400个条目, 在第二次通话之后,他们有12800个参赛作品,在50个参赛作品之后有320000个参赛作品......

答案 1 :(得分:1)

不是每次调用paintComponent时都尝试遍历元素列表,这很费时,只需更新几个单元格,考虑使用后备缓冲区,您可以直接绘制到{ {1}}上下文。

这意味着当您想要更新单元格时,更新后备缓冲区上的单个单元格并重新绘制它,这通常更有效。

此示例还检查了Graphics上下文的剪切边界,并且仅绘制了在这些边界内实际呈现的图像的数量,这进一步提高了效率。

该示例以Graphics像素大小呈现总计1,000,000个单元格(1000 x 1000),这会生成10的后备缓冲区,因此我们不会说话关于少量的价值观。

该示例允许您随机更新单元格(因为它们可以在屏幕上生成,我将其限制为前50x50单元格,以便您可以看到它们更新,但实际上它可以在整个范围内工作)

10, 000x10, 000

我放入了import java.awt.BorderLayout; 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.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.Scrollable; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class Test { public static void main(String[] args) { new Test(); } public Test() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } int cols = 1000; int rows = 1000; DrawSquare squares = new DrawSquare(cols, rows); JButton btn = new JButton("Random"); btn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int col = (int) (Math.random() * 50); int row = (int) (Math.random() * 50); System.out.println(col + "x" + row); squares.addSquare(col, row, Color.RED); squares.repaint(); } }); JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new JScrollPane(squares)); frame.add(btn, BorderLayout.SOUTH); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } class DrawSquare extends JPanel implements Scrollable { private static final long serialVersionUID = 1L; private List<Rectangle> squares = new ArrayList<Rectangle>(); private List<Color> colors = new ArrayList<Color>(); private BufferedImage img; private int cellSize; private int cols, rows; public DrawSquare(int cols, int rows) { this.cols = cols; this.rows = rows; cellSize = 10; img = new BufferedImage(cols * cellSize, rows * cellSize, BufferedImage.TYPE_INT_RGB); System.out.println(cellSize); for (int i = 0; i < cols; i++) { for (int j = 0; j < rows; j++) { addSquare(i, j, Color.WHITE); } } } public void addSquare(int col, int row, Color color) { Graphics2D g2d = img.createGraphics(); int x = col * cellSize; int y = row * cellSize; Rectangle rect = new Rectangle(x, y, cellSize, cellSize); g2d.setColor(color); g2d.fill(rect); g2d.setColor(Color.BLACK); g2d.draw(rect); g2d.dispose(); } @Override public Dimension getPreferredSize() { return new Dimension(cols * cellSize, rows * cellSize); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g.create(); Rectangle clip = g2.getClipBounds(); int width = clip.x + clip.width > img.getWidth() ? img.getWidth() - clip.x : clip.width; int height = clip.y + clip.height > img.getHeight()? img.getHeight() - clip.y : clip.height; img.getSubimage(clip.x, clip.y, width, height); g2.drawImage(img.getSubimage(clip.x, clip.y, width, height), clip.x, clip.y, this); g2.dispose(); } @Override public Dimension getPreferredScrollableViewportSize() { return new Dimension(500, 500); } @Override public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { return 128; } @Override public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { return 128; } @Override public boolean getScrollableTracksViewportWidth() { return false; } @Override public boolean getScrollableTracksViewportHeight() { return false; } } } 因为否则它不会在屏幕上呈现,或者如果我减小了单元格的大小,就会呈现为完全空白(单元格变得太小)