为什么在C#PictureBox中绘制数千个矩形要比在Java jPanel中慢得多?
在我的应用程序中,我需要在一个循环中绘制一个由数千个矩形组成的网格,而绘制性能对于视觉效果通常很重要。当我在Java中处理类似的应用程序时,我以以下方式重写了为什么在C#PictureBox中绘制数千个矩形要比在Java jPanel中慢得多?,java,c#,winforms,jpanel,drawing,Java,C#,Winforms,Jpanel,Drawing,在我的应用程序中,我需要在一个循环中绘制一个由数千个矩形组成的网格,而绘制性能对于视觉效果通常很重要。当我在Java中处理类似的应用程序时,我以以下方式重写了paintComponent方法: public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D graphics2D = (Graphics2D)g; rectanglesGrid.draw
paintComponent
方法:
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D graphics2D = (Graphics2D)g;
rectanglesGrid.draw(graphics2D);
}
rectenglesGrid
类包含一个名为cellsGrid
的二维矩形数组列表。draw
方法代码与以下代码非常相似:
public void draw(Graphics2D graphics2D)
{
for (ArrayList<Rectangle2D.Float> cells : cellsGrid)
{
for (Rectangle2D.Float cell : cells)
{
graphics2D.setPaint(someColor);
graphics2D.draw(cell);
graphics2D.fill(cell);
}
}
}
同样地,rectanglesGrid
类包含二维矩形数组,绘图方法类似于Java方法:
foreach(Rectangle[] cells in cellsGrid)
foreach(Rectangle cell in cells)
{
pen.Color = brush.Color = someColor;
graphics.DrawRectangle(pen, cell);
graphics.FillRectangle(brush, cell);
}
要强制PictureBox重新绘制,我使用计时器
并在勾选
事件处理程序调用PictureBox.Refresh()
。以这种方式在C#中绘制矩形比在Java中慢得多
我想知道为什么?我不认为这仅仅是因为“Java应用程序比C应用程序运行得更快”我在C#中的代码与Java代码非常相似,我甚至使用等效的工具进行绘图。如何在C#windows窗体应用程序中提高绘图性能?
我已经尝试将表单的双缓冲
属性设置为true,如果它确实重要的话
编辑-更好地描述我的问题 我正在做一个可视化的项目。这意味着,实际上我没有二维矩形网格,而是二维单元格网格。我将这些单元格保存在2D数组(或Java中的ArrayList)中。该单元格网格包含在类中,例如“
CellularAutomaton
”。单元格是由状态
(枚举)、矩形
、具有颜色
结构和方法的静态字段组成的结构,根据单元格状态返回正确的颜色
。在CellularAutomaton
类中的NextStep()
方法中,单元格在后续时间步中更改其状态CellularAutomaton
类还包含Draw()
方法,该方法将Graphics
实例作为参数。下面是C#中此方法的精确代码:
爪哇:
在Java中,在类I调用的TimerTask
的run
方法中:
jPanel.repaint();
cellularAutomaton.nextStep();
PictureBox
/jPanel
重新绘制会导致单元格网格被重新绘制(因为我在Java中重写了paintComponent方法,并在C#中为paint事件编写了事件处理程序,正如我前面所写的那样)
Java代码工作速度更快的示例参数:
15k 5x5矩形,每次重新喷漆和更新之间的间隔为1毫秒
NextStep()
更新
我估计,NextStep()。然而,在C#中,从CellularAutomaton
类中的单元格的2D数组中绘制200倍10k 5x5矩形大约需要1.8秒,而在Java中大约需要300毫秒。因此,正如我所想,问题是用C#绘制要慢得多。尝试将所有内容绘制成屏幕外位图,然后将该位图设置为PictureBox的图像
var bmp = new Bitmap(width, height);
using (var g = Graphics.FromImage(bmp)
{
// draw rects
}
pb.Image = bmp;
编辑
尝试使用路径执行此操作。另外,从不使用foreach
循环结构(如rect),因为它会创建它们的新实例
// generate some random rects
for (int i = 0; i < 5000; i++)
{
list.Add(new Rectangle(rnd.Next(0, pictureBox1.Width), rnd.Next(0, pictureBox1.Height), rnd.Next(1, pictureBox1.Width), rnd.Next(1, pictureBox1.Height)));
}
var bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (var g = Graphics.FromImage(bmp))
using (var path = new System.Drawing.Drawing2D.GraphicsPath())
{
path.AddRectangles(list.ToArray());
g.FillPath(Brushes.Red, path);
g.DrawPath(Pens.Black, path);
}
pictureBox1.Image = bmp;
//生成一些随机矩形
对于(int i=0;i<5000;i++)
{
添加(新矩形(rnd.Next(0,pictureBox1.Width)、rnd.Next(0,pictureBox1.Height)、rnd.Next(1,pictureBox1.Width)、rnd.Next(1,pictureBox1.Height));
}
var bmp=新位图(pictureBox1.Width,pictureBox1.Height,System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
使用(var g=Graphics.FromImage(bmp))
使用(var path=new System.Drawing.Drawing2D.GraphicsPath())
{
add矩形(list.ToArray());
g、 FillPath(画笔。红色,路径);
g、 绘图路径(钢笔、黑色、路径);
}
pictureBox1.Image=bmp;
编辑#2
以下内容在我的系统中以不到300毫秒的时间运行(未连接调试器):
私有类单元
{
公共颜色{get;set;}
公共矩形{get;set;}
}
专用小区[]小区网格;
私有随机rnd=新随机();
//生成100k个随机单元
私有void btnNextStep_单击(对象发送方,事件参数e)
{
this.cellsGrid=新单元[100000];
for(int i=0;i
我发现要提高在PictureBox
中绘制矩形的性能,最好的解决方案是使用相同的画笔颜色将矩形分组到数组中,并使用图形。FillRectangles(画笔,矩形[])
方法,而不是使用分别填充每个矩形
pictureBox.Refresh();
cellularAutomaton.NextStep();
jPanel.repaint();
cellularAutomaton.nextStep();
var bmp = new Bitmap(width, height);
using (var g = Graphics.FromImage(bmp)
{
// draw rects
}
pb.Image = bmp;
// generate some random rects
for (int i = 0; i < 5000; i++)
{
list.Add(new Rectangle(rnd.Next(0, pictureBox1.Width), rnd.Next(0, pictureBox1.Height), rnd.Next(1, pictureBox1.Width), rnd.Next(1, pictureBox1.Height)));
}
var bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (var g = Graphics.FromImage(bmp))
using (var path = new System.Drawing.Drawing2D.GraphicsPath())
{
path.AddRectangles(list.ToArray());
g.FillPath(Brushes.Red, path);
g.DrawPath(Pens.Black, path);
}
pictureBox1.Image = bmp;
private class Cell
{
public Color Color { get; set; }
public Rectangle Rectangle { get; set; }
}
private Cell[] cellsGrid;
private Random rnd = new Random();
// generate 100k random cells
private void btnNextStep_Click(object sender, EventArgs e)
{
this.cellsGrid = new Cell[100000];
for (int i = 0; i < this.cellsGrid.Length; i++)
{
this.cellsGrid[i] = new Cell()
{
Color = Color.FromArgb(rnd.Next()),
Rectangle = new Rectangle(rnd.Next(0, pictureBox1.Width), rnd.Next(0, pictureBox1.Height), rnd.Next(1, 5), rnd.Next(1, 5))
};
}
this.DrawCells();
}
// draw them and measure time taken
private void DrawCells()
{
var start = DateTime.Now;
var bmp = new Bitmap(this.pictureBox1.Width, this.pictureBox1.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (var g = Graphics.FromImage(bmp))
using (var p = new Pen(Color.Black))
using (var b = new SolidBrush(Color.Black))
{
for (int i = 0; i < this.cellsGrid.Length; i++)
{
b.Color = this.cellsGrid[i].Color;
g.FillRectangle(b, this.cellsGrid[i].Rectangle);
p.Color = this.cellsGrid[i].Color;
g.DrawRectangle(p, this.cellsGrid[i].Rectangle);
}
}
this.pictureBox1.Image = bmp;
MessageBox.Show((DateTime.Now - start).TotalSeconds.ToString());
}