http://blog.csdn.net/fanerde/article/details/3136670
由於項目需要,要使用c#描畫高頻實時曲線.
但是在C#下由於描畫圖像使用的是GDI+,描畫效率很有問題.一旦曲線太多,就會造成CPU使用率直線上升,馬上飆升到100%.
在GDI+下使用雙緩沖也無濟於事,雙緩沖本身只會解決曲線多的時候全屏閃爍問題,但描畫效率還是嚴重低下.
其間用過多種解決方案:DRECT3D,DRIRECT2D,GDI,,,,,等等等等
最後從效率出發,最終解決方案如下:
前台顯示使用GDI,而後台描畫則采用GDI+
後台采用10倍於前台窗口的BUFFER,每次向其中畫一條線.然後通過一個RECT視口,每次向前台顯示視口裡的內容.否則每次重繪的代價太高.
這個方法實現的難點主要在於GDI和GDI+的結合部分,主要代碼如下:
1.函數庫:using 和 WIN32API函數
using System.Runtime.InteropServices; using System.Drawing; using System.Drawing.Imaging; using System.Drawing.Drawing2D; using System.Drawing.Text; [DllImport("gdi32")] public static extern IntPtr CreateCompatibleDC(IntPtr hdc); [DllImport("gdi32")] public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject); [DllImport("GDI32.dll")] public static extern long BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop); [DllImport("GDI32.dll")] public static extern bool DeleteObject(IntPtr hObject);
public PictureBox _backgroundGraph;//被描畫的控件對象 //public Form _backgroundGraph; public Graphics _backgroundGraphic = null; // 背景Graphic public Graphics _backgroundRenderGraphic = null; // 雙緩沖Graphic private Graphics _backgroundMemoryGraphic = null; // 內存Graphic public Graphics _backgroundDrawGraphic = null; // 描畫Graphic private Bitmap _backgroundMemoryBitmap = null; // 內存Bitmap public BufferedGraphics _graphicsBuffer = null; // 雙緩沖BufferedGraphics private IntPtr _memoryGraphicHdc; // 內存Graphic適用的引用 private IntPtr _memoryBitmapHdc; // 內存Bitmap適用的引用
public void InitDraw() { _backgroundGraph = pictureBox1; lock (_backgroundGraph) { if (null != _backgroundGraphic) { _backgroundGraphic.Dispose(); } if (null != _graphicsBuffer) { _graphicsBuffer.Dispose(); } if (null != _backgroundRenderGraphic) { _backgroundRenderGraphic.Dispose(); } if (null != _backgroundMemoryBitmap) { DeleteObject(_memoryBitmapHdc); _backgroundMemoryBitmap.Dispose(); } if (null != _backgroundMemoryGraphic) { DeleteObject(_memoryGraphicHdc); _backgroundMemoryGraphic.Dispose(); } if (null != _backgroundDrawGraphic) { _backgroundDrawGraphic.Dispose(); } // 背景Graphic _backgroundGraphic = _backgroundGraph.CreateGraphics(); BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current; _graphicsBuffer = currentContext.Allocate(_backgroundGraphic, _backgroundGraph.ClientRectangle); // 雙緩沖Graphic _backgroundRenderGraphic = _graphicsBuffer.Graphics; _backgroundRenderGraphic.Clear(Color.White); _backgroundRenderGraphic.SetClip(_backgroundGraph.ClientRectangle); // 內存Bitmap _backgroundMemoryBitmap = new Bitmap(_backgroundGraph.ClientRectangle.Width * 10, _backgroundGraph.ClientRectangle.Height, _backgroundRenderGraphic); // 內存Graphic _backgroundMemoryGraphic = Graphics.FromImage(_backgroundMemoryBitmap); _backgroundMemoryGraphic.Clear(Color.White); // 創建適用的繪圖區 _memoryGraphicHdc = CreateCompatibleDC(_backgroundMemoryGraphic.GetHdc()); _memoryBitmapHdc = _backgroundMemoryBitmap.GetHbitmap(); SelectObject(_memoryGraphicHdc, _memoryBitmapHdc); // 描畫Graphic _backgroundDrawGraphic = Graphics.FromHdc(_memoryGraphicHdc); _backgroundDrawGraphic.SmoothingMode = SmoothingMode.HighQuality; _backgroundDrawGraphic.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; _backgroundDrawGraphic.InterpolationMode = InterpolationMode.HighQualityBilinear; _backgroundDrawGraphic.PixelOffsetMode = PixelOffsetMode.HighQuality; } }
ublic void DrawSomething() { _backgroundDrawGraphic.DrawLine(System.Drawing.Pens.Black, 0, 0, 100, 100); }
public void UpdateView() { IntPtr memHdc = _backgroundDrawGraphic.GetHdc(); IntPtr renHdc = _backgroundRenderGraphic.GetHdc(); BitBlt(renHdc, 0, 0, 100, 100, memHdc, 0, 0, 0xCC0020); _backgroundDrawGraphic.ReleaseHdc(); _backgroundRenderGraphic.ReleaseHdc(); _graphicsBuffer.Render(_backgroundGraphic); }