三个System.Drawing方法表现出慢速绘制或闪烁:解决方案? 或其他选择?

我正在通过System.Drawing进行一些小图表,我遇到了一些问题。

我在队列中保存数据,我正在将这些数据绘制(绘制)到三个图片框上

此方法填充图片框,然后滚动图表。

所以不要在之前的图纸上画画(并且看起来更加混乱)我找到了2个绘制图形的解决方案。

  1. 在绘制循环之前调用plot.Clear(BACKGOUNDCOLOR) [块注释]

虽然这会导致从实际绘制循环所需的时间出现闪烁。

  1. call plot.DrawLine(channelPen[5], j, 140, j, 0); 就在每条画线之前[评论]

虽然这会导致绘图开始正常,然后非常快速地减速到爬行,就好像在绘制命令之前放置了等待命令一样。

以下是供参考的代码:

 /*plotx.Clear(BACKGOUNDCOLOR) ploty.Clear(BACKGOUNDCOLOR) plotz.Clear(BACKGOUNDCOLOR)*/ for (int j = 1; j  RealTimeBuffer.Count - 1) break; QueueEntity past = RealTimeBuffer.ElementAt(j - 1); QueueEntity current = RealTimeBuffer.ElementAt(j); if (j == 1) { //plotx.DrawLine(channelPen[5], 0, 140, 0, 0); //ploty.DrawLine(channelPen[5], 0, 140, 0, 0); //plotz.DrawLine(channelPen[5], 0, 140, 0, 0); } //plotx.DrawLine(channelPen[5], j, 140, j, 0); plotx.DrawLine(channelPen[0], j - 1, (((past.accdata.X - 0x7FFF) / 256) + 64), j, (((current.accdata.X - 0x7FFF) / 256) + 64)); //ploty.DrawLine(channelPen[5], j, 140, j, 0); ploty.DrawLine(channelPen[1], j - 1, (((past.accdata.Y - 0x7FFF) / 256) + 64), j, (((current.accdata.Y - 0x7FFF) / 256) + 64)); //plotz.DrawLine(markerPen, j, 140, j, 0); plotz.DrawLine(channelPen[2], j - 1, (((past.accdata.Z - 0x7FFF) / 256) + 94), j, (((current.accdata.Z - 0x7FFF) / 256) + 94)); } 

是否有任何技巧可以避免这些开销?

如果没有,是否会有其他/更好的解决方案?

编辑:有关解决方案代码,请参阅下面的[最终解决方案]

PictureBox已经启用了双缓冲。 您可以感知闪烁的唯一方法是直接绘制到屏幕而不是使用Paint事件。 目前尚不清楚你是否使用你的代码片段。 使用位图缓冲自己也会起作用,但效率不如Windows Forms实现的双缓冲。

在数据更改时调用其Invalidate()方法,在Paint事件中执行绘图(使用e.Graphics)并且它不会闪烁。

在将数据放入图片框之前,尝试将数据缓冲到另一个位图。 这将消除闪烁。

例如:

 // create this once for each graph Bitmap buffer = new Bitmap({width}, {height}); // when the data changes using (Graphics g = Graphics.FromImage(buffer)) { // ... draw using the graphics } // draw the buffer on the picture box's image 

你是在一个单独的线程上绘图吗? 您每秒抽取数据多少次? 如果您在主线程上执行此操作或者每秒重复绘制整个位图,您的程序会感觉很慢。

对图片框进行子类化并启用双缓冲区选项。

公共类MyBufferedPictureBoxinheritanceSystem.Windows.Forms.PictureBox

 Public Sub New() MyBase.New() Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True) End Sub 

结束类

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.setstyle.aspx

我会使用双缓冲方法。 在内存中创建一个新的位图(与图形大小相同)创建该位图的图形对象。

然后在该对象上绘制您想要的任何内容。

完成所有绘图后,从pictureBox创建另一个图形对象,并使用DrawImage绘制内存中的位图。

这应该可以减少闪烁,因为除了一个更新整个图像的大绘图之外,您绘制了屏幕的所有内容。

希望能帮助到你。

[最终解决方案]

即使使用重复循环也使用paint事件足够快!

在结束而不是复制每个事件中的绘制循环,我使用第一个事件也将其他两个图形绘制到位图,然后在他们的绘图事件上,简单地绘制位图。

所以基本上最终的解决方案是你的许多答案的组合。

谢谢你们。

 private void pictureBoxAccX_Paint(object sender, PaintEventArgs e) { bufferedploty.Clear(Color.Black); bufferedplotz.Clear(Color.Black); for (int j = 1; j < 599; j++) { if (j > RealTimeBuffer.Count - 1) break; QueueEntity past = RealTimeBuffer.ElementAt(j - 1); QueueEntity current = RealTimeBuffer.ElementAt(j); e.Graphics.DrawLine(channelPen[0], j - 1, (((past.accdata.X - 0x7FFF) / 256) + 64), j, (((current.accdata.X - 0x7FFF) / 256) + 64)); bufferedploty.DrawLine(channelPen[1], j - 1, (((past.accdata.Y - 0x7FFF) / 256) + 64), j, (((current.accdata.Y - 0x7FFF) / 256) + 64)); bufferedplotz.DrawLine(channelPen[2], j - 1, (((past.accdata.Z - 0x7FFF) / 256) + 94), j, (((current.accdata.Z - 0x7FFF) / 256) + 94)); } } private void pictureBoxAccY_Paint(object sender, PaintEventArgs e) { e.Graphics.DrawImage(BufferedBitMapy, new Point(0, 0)); } private void pictureBoxAccZ_Paint(object sender, PaintEventArgs e) { e.Graphics.DrawImage(BufferedBitMapz, new Point(0, 0)); } private void AddAccPoints() { //Code for putting in New queue data Here... pictureBoxAccX.Invalidate(); pictureBoxAccY.Invalidate(); pictureBoxAccZ.Invalidate(); } 

编辑:使用这个精确的解决方案使控件无效可能导致事件调度未定义并随机停止绘制,因为位图创建在一个事件方法中完成。

请参见此处: Onpaint事件(无效)在句点正常操作(运行时)后更改执行顺序