为什么在C#PictureBox中绘制数千个矩形要比在Java jPanel中慢得多?

为什么在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

在我的应用程序中,我需要在一个循环中绘制一个由数千个矩形组成的网格,而绘制性能对于视觉效果通常很重要。当我在Java中处理类似的应用程序时,我以以下方式重写了
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());
}