C#下实现双缓冲描画高频曲线(GDI+结合GDI)

来源:互联网 发布:公交地图软件 编辑:程序博客网 时间:2024/05/01 00:20

由于项目需要,要使用c#描画高频实时曲线.

但是在C#下由于描画图像使用的是GDI+,描画效率很有问题.一旦曲线太多,就会造成CPU使用率直线上升,马上飙升到100%.

在GDI+下使用双缓冲也无济于事,双缓冲本身只会解决曲线多的时候全屏闪烁问题,但描画效率还是严重低下.

其间用过多种解决方案:DRECT3D,DRIRECT2D,GDI,,,,,等等等等

最后从效率出发,最终解决方案如下:

前台显示使用GDI,而后台描画则采用GDI+

后台采用10倍于前台窗口的BUFFER,每次向其中画一条线.然后通过一个RECT视口,每次向前台显示视口里的内容.否则每次重绘的代价太高.

这个方法实现的难点主要在于GDI和GDI+的结合部分,主要代码如下:

1.函数库:using 和 WIN32API函数

  1. using System.Runtime.InteropServices;
  2. using System.Drawing;
  3. using System.Drawing.Imaging;
  4. using System.Drawing.Drawing2D;
  5. using System.Drawing.Text;
  6. [DllImport("gdi32")]
  7. public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
  8. [DllImport("gdi32")]
  9. public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject);
  10. [DllImport("GDI32.dll")]
  11. public static extern long BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
  12. [DllImport("GDI32.dll")]
  13. public static extern bool DeleteObject(IntPtr hObject);

2.声明对象

  1. public PictureBox _backgroundGraph;//被描画的控件对象
  2. //public Form _backgroundGraph;
  3. public Graphics _backgroundGraphic = null// 背景Graphic
  4. public Graphics _backgroundRenderGraphic = null// 双缓冲Graphic
  5. private Graphics _backgroundMemoryGraphic = null// 内存Graphic
  6. public Graphics _backgroundDrawGraphic = null// 描画Graphic
  7. private Bitmap _backgroundMemoryBitmap = null// 内存Bitmap
  8. public BufferedGraphics _graphicsBuffer = null// 双缓冲BufferedGraphics
  9. private IntPtr _memoryGraphicHdc; // 内存Graphic适用的引用
  10. private IntPtr _memoryBitmapHdc; // 内存Bitmap适用的引用

3.初始化对象

  1.    public void InitDraw()
  2.         {
  3.             _backgroundGraph = pictureBox1;
  4.             lock (_backgroundGraph)
  5.             {
  6.                 if (null != _backgroundGraphic)
  7.                 {
  8.                     _backgroundGraphic.Dispose();
  9.                 }
  10.                 if (null != _graphicsBuffer)
  11.                 {
  12.                     _graphicsBuffer.Dispose();
  13.                 }
  14.                 if (null != _backgroundRenderGraphic)
  15.                 {
  16.                     _backgroundRenderGraphic.Dispose();
  17.                 }
  18.                 if (null != _backgroundMemoryBitmap)
  19.                 {
  20.                     DeleteObject(_memoryBitmapHdc);
  21.                     _backgroundMemoryBitmap.Dispose();
  22.                 }
  23.                 if (null != _backgroundMemoryGraphic)
  24.                 {
  25.                     DeleteObject(_memoryGraphicHdc);
  26.                     _backgroundMemoryGraphic.Dispose();
  27.                 }
  28.                 if (null != _backgroundDrawGraphic)
  29.                 {
  30.                     _backgroundDrawGraphic.Dispose();
  31.                 }
  32.                 // 背景Graphic
  33.                 _backgroundGraphic = _backgroundGraph.CreateGraphics();
  34.                 BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
  35.                 _graphicsBuffer = currentContext.Allocate(_backgroundGraphic, _backgroundGraph.ClientRectangle);
  36.                 // 双缓冲Graphic
  37.                 _backgroundRenderGraphic = _graphicsBuffer.Graphics;
  38.                 _backgroundRenderGraphic.Clear(Color.White);
  39.                 _backgroundRenderGraphic.SetClip(_backgroundGraph.ClientRectangle);
  40.                 // 内存Bitmap
  41.                 _backgroundMemoryBitmap = new Bitmap(_backgroundGraph.ClientRectangle.Width * 10, _backgroundGraph.ClientRectangle.Height, _backgroundRenderGraphic);
  42.                 // 内存Graphic
  43.                 _backgroundMemoryGraphic = Graphics.FromImage(_backgroundMemoryBitmap);
  44.                 _backgroundMemoryGraphic.Clear(Color.White);
  45.                 // 创建适用的绘图区
  46.                 _memoryGraphicHdc = CreateCompatibleDC(_backgroundMemoryGraphic.GetHdc());
  47.                 _memoryBitmapHdc = _backgroundMemoryBitmap.GetHbitmap();
  48.                 SelectObject(_memoryGraphicHdc, _memoryBitmapHdc);
  49.                 // 描画Graphic
  50.                 _backgroundDrawGraphic = Graphics.FromHdc(_memoryGraphicHdc);
  51.                 _backgroundDrawGraphic.SmoothingMode = SmoothingMode.HighQuality;
  52.                 _backgroundDrawGraphic.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
  53.                 _backgroundDrawGraphic.InterpolationMode = InterpolationMode.HighQualityBilinear;
  54.                 _backgroundDrawGraphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
  55.             }
  56.         }

4.使用GDI+描画曲线

  1.  public void DrawSomething()
  2.         {
  3.             _backgroundDrawGraphic.DrawLine(System.Drawing.Pens.Black, 0, 0, 100, 100);
  4.         }

5.使用bitblt向前台描画

  1.    public void UpdateView()
  2.         {
  3.             IntPtr memHdc = _backgroundDrawGraphic.GetHdc();
  4.             IntPtr renHdc = _backgroundRenderGraphic.GetHdc();
  5.             BitBlt(renHdc, 0, 0, 100,
  6.             100, memHdc, 0, 0, 0xCC0020);
  7.             _backgroundDrawGraphic.ReleaseHdc();
  8.             _backgroundRenderGraphic.ReleaseHdc();
  9.             _graphicsBuffer.Render(_backgroundGraphic);
  10.         }

 

 

 

 

 

原创粉丝点击