我正在开发一个模拟元胞自动机的应用程序。碰巧我需要画得非常快(每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));
}
}
}
答案 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;
}
}
}
因为否则它不会在屏幕上呈现,或者如果我减小了单元格的大小,就会呈现为完全空白(单元格变得太小)