【问题标题】:C# Winform refresh image cause delayC# Winform 刷新图像导致延迟
【发布时间】:2019-12-06 05:31:54
【问题描述】:

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

所以,现在我的问题是我将计时器的间隔设置为 50 毫秒或 100 毫秒,但是有一个延迟,导致图像不会以我想要的速度更新。

我知道创建新位图会导致延迟,但我没有找到替换它的方法。我在想我可以在一开始就绘制整个心电图数据的位图,并在计时器滴答时将其向左移动,但我找不到一种方法来将位图移动到图片框中。

有人知道这个问题吗?

下面是我的paint方法的代码。

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,numberOfCellY 小于 8,并且我用秒表测试了仅用了 2ms 的绘制方法的运行时间。

我还测试了整个迭代的运行时间,包括更新图像和绘制它需要 27 毫秒。所以当我将 Timer 的间隔设置为 100 毫秒时。完成一个 Tick 大约需要 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);

定时器代码: 更新grid和points的坐标,调用Invalidate刷新picturebox。

【问题讨论】:

  • 嗨,欢迎来到堆栈溢出。请参阅How to Ask 链接以获取有关如何提出问题并相应更新您的问题的更多详细信息。例如,添加您制作的代码的最小版本。
  • 直接在 PictureBox 表面上绘画(使用PaintEventArgs'e.Graphics 对象),这里不需要位图。您可以将绘图过程移动到一个独立的方法;将e.Graphics 传递给此方法。如果/当您需要在 Bitmap 上修复绘图时,请传递从 Bitmap 派生的 Graphics 对象。顺便说一句,您的代码无法测试,缺少太多部分。
  • 感谢您的建议,我把Bitmap的代码去掉,直接在PictureBox上画线。但是,延迟仍然存在。我只能达到 125 毫秒的时间间隔,最多每秒 8 帧,没有延迟。
  • 您尚未使用您应用的修改更新问题中的代码,因此看不到问题(如果有的话)。如果您更新它或发布新问题来解决问题,了解numOfLabelsnumOfCellsYnumOfCellsX 等的实际值会很有用。平均迭代次数非常重要。
  • 对不起,我刚刚注意到了。现在更新了。

标签: c# winforms


【解决方案1】:

DrawArea 是一种非托管的 ref 类型,但您没有释放它。

在 .net 的引擎盖下,您正在对 GC 施加压力。您可以在 CLR 分析器中看到 Gen2 已达到最大值。 GC 正在尝试释放内存,但 Dispose、Collection、Resurrection 和 final malloc 花费的时间超过 50 毫秒。

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

【讨论】:

  • 我在想也许直接在面板上绘图会更快,没有位图和图片框?
  • 感谢您的帮助!实际上,每次当我的计时器调用无效时,我想我会创建一个新的位图并将其分配给 DrawArea 变量。 (我认为这会处理旧的),我是Winform的新手,如果我错了,请纠正我。
  • 当然你可以尝试一下,也许可以通过将 DrawArea 设置为类的私有成员变量来将其性能与相反的情况进行比较。
  • 我尝试直接在 Picturebox 上画线,但延迟仍然存在。我可以为我的计时器设置的最低间隔是 125 毫秒,没有任何延迟。如果我将间隔设置得较低,延迟会随着时间的推移而增加(例如,延迟一开始是 2 秒,但会在 1 分钟后增加到 10 秒)。因此,我想知道其他地方可能有一些错误,但我不知道它在哪里......
  • 当 Paint 事件自行失效时,为什么还要有一个 Timer?也请edit您的问题显示更新的代码并指定标签和行数。
【解决方案2】:

我找到了一种解决问题的愚蠢方法。假设我有一秒钟要绘制 240 个数据点,如果我将计时器的间隔设置为 50 毫秒,我需要为每个 Tick 绘制 240/20 = 12 个点,以便在一秒钟内绘制 240 个点.

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-08
    • 1970-01-01
    • 2018-07-31
    • 2015-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多