我正在研究一个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刷新图片框。
答案 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点来解决问题。