C#Winform刷新图像导致延迟

时间:2019-12-06 05:31:54

标签: c# winforms

我正在研究一个ECG项目,该项目实时显示ECG图。我在图片框中绘制了图像。我用来更新图像的方式是使用Forms.Timer调用Invalidate()来刷新和更新picturebox中的图像。在picturebox_paintmethod中,我创建了一个新的Bitmap并使用图形绘制了ECG的新线和网格每次。

所以,现在我的问题是我将计时器的间隔设置为50ms或100ms,但是有一个延迟,该延迟使图像无法按照我想要的速率进行更新。

我知道创建新的位图会导致延迟,但是我没有找到替换它的方法。我本以为可以从一开始就绘制整个Ecg数据的位图,并在计时器打勾时将其移到左侧,但是我找不到一种只在Picturebox中移动位图的方法。

有人对这个问题有想法吗?

下面是我的绘画方法的代码。

private void pictureBox1_paint(object sender, PaintEventArgs e){
            // Draw the ECG.
            DrawArea = new Bitmap(pictureBox1.Size.Width,pictureBox1.Size.Height);
            using (g = Graphics.FromImage(DrawArea))
            {
                //dispose the original image.
                if (pictureBox1.Image != null)
                {
                    pictureBox1.Image.Dispose();
                }


                // draw the labels
                int numOfLabels = ((numOfCellsX - numOfCellsX % 4) / 4) * 2;

                for (int l = 0; l < numOfLabels; l++)
                {
                    g.DrawString((labelV).ToString(), drawFont, drawBrush, (unitOfLabel * l) + changeValueOfLabel, viewsizeY - 20);
                    labelV = labelV + unitOfLabel;
                }
                labelV -= numOfLabels * unitOfLabel;

                // draw horizontal lines of gird
                for (int y = 0; y <= numOfCellsY; ++y)
                {
                    g.DrawLine(bgp, 0, y * cellSizeY, viewsizeX, y * cellSizeY);
                }

                // draw vertical lines of gri, +6 because here we are drawing 6 more lines on the right of the grid for further moving.
                for (int x = 1; x <= numOfCellsX * 2; ++x)
                {
                    g.DrawLine(bgp, (x * cellSizeX) + changeValue, 0, (x * cellSizeX) + changeValue, viewsizeY);
                }

                //drawPoints
                g.DrawLines(mypen, points);

                //draw the most top line
                //g.DrawLine(bgp, viewsizeX - 1, 0, viewsizeX - 1, viewsizeY);
                // draw the most right line
                g.DrawLine(bgp, viewsizeX - 1, 0, viewsizeX - 1, viewsizeY);
                //draw the most left line
                g.DrawLine(bgp, 0, 0, 0, viewsizeY);
                // draw the bottom line, the reason that draw those line outside the for loop, is because the location.X of
                // the most left point of the picturebox is actually 599, therefore,it cannot display the 600 index point.
                g.DrawLine(bgp, 0, viewsizeY - 1, viewsizeX, viewsizeY - 1);

                // replace the image of the picturebox
                pictureBox1.Image = DrawArea;
            }
        }

numberOfCellX和numberofLabel小于15,numberOfCellYis小于8,我已经使用秒表测试了绘制方法的运行时间,该过程仅花费2毫秒。

我还测试了整个迭代的运行时间,包括更新图像和绘制图像,这花费了27ms。因此,当我将Timer的间隔设置为100ms时。完成一滴答声大约需要127毫秒。

不使用位图的更新代码:

// Draw the ECG.
        g = e.Graphics;

            if (pictureBox1.Image != null)
            {
                pictureBox1.Image.Dispose();
            }


            // draw the labels
            int numOfLabels = ((numOfCellsX - numOfCellsX % 4) / 4) * 2;

            for (int l = 0; l < numOfLabels; l++)
            {
                g.DrawString((labelV).ToString(), drawFont, drawBrush, (unitOfLabel * l) + changeValueOfLabel, viewsizeY - 20);
                labelV = labelV + unitOfLabel;
            }

            labelV -= numOfLabels * unitOfLabel;


            // draw horizontal lines of gird
            for (int y = 0; y <= numOfCellsY; ++y)
            {
                g.DrawLine(bgp, 0, y * cellSizeY, viewsizeX, y * cellSizeY);
            }

            // draw vertical lines of gri, +6 because here we are drawing 6 more lines on the right of the grid for further moving.
            for (int x = 1; x <= numOfCellsX * 2; ++x)
            {
                g.DrawLine(bgp, (x * cellSizeX) + changeValue, 0, (x * cellSizeX) + changeValue, viewsizeY);
            }

            //drawPoints
            g.DrawLines(mypen, points);

            //draw the most top line
            //g.DrawLine(bgp, viewsizeX - 1, 0, viewsizeX - 1, viewsizeY);
            // draw the most right line
            g.DrawLine(bgp, viewsizeX - 1, 0, viewsizeX - 1, viewsizeY);
            //draw the most left line
            g.DrawLine(bgp, 0, 0, 0, viewsizeY);
            // draw the bottom line, the reason that draw those line outside the for loop, is because the location.X of
            // the most left point of the picturebox is actually 599, therefore,it cannot display the 600 index point.
            g.DrawLine(bgp, 0, viewsizeY - 1, viewsizeX, viewsizeY - 1);

计时器代码:      更新网格和点的坐标,然后调用Invalidate刷新图片框。

2 个答案:

答案 0 :(得分:1)

DrawArea是非托管的引用类型,但您不打算丢弃它。

在.net的内部,您给GC施加了压力。您可以在CLR分析器中看到Gen2正在耗尽。 GC正在尝试释放内存,但“处置”,“收集”,“复活”和最终的malloc占用的时间超过50ms。

将DrawArea放置在using中,或者在完成使用后在末尾显式调用dispose:DrawArea.Dispose();

答案 1 :(得分:0)

我找到了解决问题的一种愚蠢的方法。假设我在一秒钟内有240点数据要绘制,并且如果我将计时器的间隔设置为50ms,则我需要为每个刻度线在图片上绘制240/20 = 12点,以便在一秒钟内绘制240点

但是,在这种情况下,我发现由于延迟而需要大约1.25秒才能绘制240点。因此,我使用的愚蠢方法是为每个计时器滴答声绘制12 * 1.25 = 15点。然后我可以在一秒钟内画出240点来解决问题。