C#中怎样实现mfc在内存dc绘图,以避免绘图时的闪烁

源码开发语言/平台
当前位置:
& 免费下载
最新本分类资源
是否想不用第三方控件就能自制换肤界面,这个程序可以方便的实现。 ...
这是一本学习AUTOCAD的难得的好书,希望对大家学习有用。
根据工程数据点进行贝塞尔曲线拟合的程序,进行拟合后直接在FORM上绘制贝塞尔曲线 ...
通过最小二乘法 实现2次曲线拟合,利用工程数学解二次函数 的各系数,然后画出曲线图 ...
仿真LCD的输出,有时我们程序当中要仿真工业的LCD显示,可用这个源程序仿真 ...
编写的一个工业用计量器具的显示窗口,可用于仿真一个数字摆针 ...
绘制样条曲线的源代码,供大家学习交流之用。
很好的一个计算机绘图软件,使用非常方便!
以下功能:
1.自定义颜色功能
2.自定义线的宽度,顔色,格式的功能
3.自定义文字的颜 ...
自己编的一个简单的画直线程序,刚才那个有问题,这个是完整的了 ...
本类热门下载
VC++6.0的实时曲线图表程序.随着输入数据的变化,图表曲线随之实时的上下波动. ...
丰富的图形类型(直线,平行四边形,矩形,多边形,圆角矩形,圆,椭圆,二次均匀B样 ...
完整的基本图形绘制系统
C#+绘制实时曲线包括绘制坐标轴,C#+绘制实时曲线包括绘制坐标轴 ...
绘制实时曲线的源代码,用 VC 6.0 环境编制。
非常好用的绘图控件,不用破解,可以直接使用,安装后,并且附带实例代码!适合所有开 ...
在Visual C++中实现的Sutherland-Hodgman多边形裁剪算法
实时曲线绘制的类clPlot,在vc环境下实现曲线图形,vc++以曲线形式实时动态显示数据的控 ...
最新VC++绘图程序设计技巧与实例教程 PDF格式
开源的超好国产cad
CopyRight &
verySource.Com All Rights reserved.  京公网安备:882D绘图引擎比较
&&&&&&&&&&
这个问题很普遍。最近在研究这个问题,在网上搜了一些资料,再结合自己的经验,谈谈自己的一些想法。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
一.双缓存能提高绘图效率吗?
网上有篇文章:,其中提到一种方法是:1.
缓存——Bitmap或者DoubleBuffer。缓存就是先把绘制的图形绘制到一张内存位图上,然后在一次性的贴位图,他可以提高绘图速度,也能避免闪烁。DoubleBuffer=true是C#窗体的属性,设置了此属性估计系统本身会起用无效区的内存位图缓存,而不需要程序员Bitmap处理。
这里对双缓存的通常做法不作介绍,网上的相关资料很多。说实话,我对使用双缓存能提升绘图效率表示怀疑,理由很简单,同是DC,同是绘制1000条线段,有什么理由内存DC就比窗口DC快(当然这个我没有作具体的测试,这个有空可以测试下)。我还稍微怀疑使用双缓存绘图比直接使用窗口DC绘图还慢一些,理由有二:一是使用双缓存需要增加创建内存DC和内存位图的操作;二是使用双缓存还需要增加一个把内存DC拷贝到窗口DC的操作。那么双缓存的主要作用是什么?其实就是解决绘图过程的闪烁问题,改善绘图效果。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
二.Windows环境下二维绘图引擎的选取
和绘图效率的一个重要相关因素是绘图引擎。Windows环境下二维绘图引擎有多种选择:GDI、GDI+、DirectDraw、QT、Agg、Cairo、skia、Direct2D、Direct3D、OpenGL等。下面我逐一作一个简单的分析:
GDI:微软原生的二维绘图引擎。
优点:微软的全力支持,作为操作系统核心层效率方面不用担心,支持多种开发框架(含语言):Win
SDK、MFC、Delphi等。
缺点:基于过程,缺乏面向对象,使用起来不太方便,不支持反锯齿,不支持复杂的绘图效果(这个相对于GDI+而言)。
GDI+:微软后来推出的二维绘图引擎。
优点:微软的全力支持,支持多种开发框架(含语言):Win
SDK、MFC、Delphi等,可以实现复杂的绘图效果,如反锯齿、路径画刷等;面向对象的架构,使用起来比较方便。
缺点:绘图效率较GDI稍低,绘图交互性不如GDI(缺少GDI的支持位运算的绘图模式),开启反锯齿后效率不如QT。
有关GDI和GDI+的详细比较,请看我以前写的一篇文章:。
DirectDraw:从GDI、GDI+到Direct
2D的一个过渡产品,微软已明确表示不推荐使用,在MicrosoftDirectX SDK (June
2010)已看不到它的身影,在此不作介绍。
QT:开源跨平台(基于LGPL协议),面向对象的方式组织,使用起来较为方便。
Agg:C++编写的开源绘图引擎(基于GPL协议)
Cairo:C编写的开源绘图引擎(基于LGPL协议),大名鼎鼎的FireFox就是用这个绘图引擎的。
有关Agg和Cairo请参考这篇文章:。该文作者比较推崇Cairo,但据我公司的一个同事介绍:Cairo的绘图效率很慢。具体我没有做过测试。
Skia:Google的Android的绘图引擎。&&
Direct2D:微软在WindowsVista及之后的Windows版本推出的意在取代GDI、GDI+的二维绘图引擎,支持硬件加速。
Direct3D:微软开发的3D绘图引擎。
OpenGL:SGI开发的3D绘图引擎。
上面简单对Windows下的二维绘图引擎作了一个简单介绍。我的推荐是:开发商业产品一般情况下在Windows
XP及以下Windows版本使用GDI和GDI+,在Windows Vista及其之后的Windows版本(如Win
7)使用Direct2D。理由是:跨平台的绘图引擎如Agg、Cairo之类的,出于跨平台封装的需要,必然会牺牲一部分性能,就是说它本来就是封装GDI的,怎么可能超出GDI的绘图效率呢?还有就是诸如Agg还有开源协议的限制,这样就排除了开源二维绘图引擎。我也不推荐使用Direct3D、OpenGL等三维绘图引擎进行二维绘图,理由是三维绘图可以利用硬件加速,绘图速度应该比GDI、GDI+快,但三维绘图引擎一般是基于三维的数据结构进行组织的,对二维绘图并不合适,比如以前我们曾利用OpenGL进行二维绘图,发现OpenGL在二维一些操作并不合适,如二维中的点、线捕捉、自定义图例的添加、打印的支持等等。所以我倾向于使用GDI、GDI+。GDI的一大缺点是由于不是面向对象组织的,使用起来较为繁琐。这个我觉得可以参考GDI+的面向对象封装的方式对GDI进行封装。Direct
2D是微软在后XP时代开发的开发二维绘图引擎。微软出于兼容性的考虑还会继续对GDI、GDI+进行支持,但毫无疑问微软的策略是要Direct
2D取代GDI和GDI+的,因此在WindowsVista及其之后的Windows上进行二维绘图开发我建议是直接使用Direct2D。Direct
2D支持硬件加速,在绘图效率应有一定程度的提升。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
三.提高GDI绘图效率的常用做法
提高GDI绘图效率的一般原则可以简单概括为:尽量减少无效绘图区域,尽量减少不必要的绘图操作。
尽量减少绘图区域的通常做法是:
设置裁剪区。裁剪区的作用就是:只有在这个区内的绘图过程才会真正有效,在区外的是无效的,即使在区外执行了绘图函数也是不会显示的。因为多数情况下窗口重绘的产生大多是因为窗口部分被遮挡或者窗口有滚动发生,改变的区域并不是整个图形而只有一小部分,这一部分需要改变的就是pDC中的裁剪区了。因为显示(往内存或者显存都叫显示)比绘图过程的计算要费时得多,有了裁剪区后显示的就只是应该显示的部分,大大提高了显示效率。但是这个裁剪区是MFC设置的,它已经为我们提高了显示效率,在进行复杂图形的绘制时如何进一步提高效率呢?那就只有去掉在裁剪区外的绘图过程了。可以先用pDC-&GetClipBox()得到裁剪区,然后在绘图时判断你的图形是否在这个区内,如果在就画,不在就不画。
减少无效区域。在GDI绘图中,被标记为无效矩形的区域直到WM_PAINT消息被处理完之后才会消失。因此在绘图中应尽量避免使用Invalidate函数(该函数使整个客户区设置为无效区域),而应在多使用InvalidateRect函数具体比如你想改变某条线的线型,应首先精确计算改线的屏幕范围,然后改变其线型后调用InvalidateRect函数进行局部更新。
尽量减少不必要的绘图操作。比如二维矢量绘图中一般有一个滑动鼠标滚轮进行全图缩放的操作。其实在缩放过程中,每一次WM_MOUSEWHEEL消息的处理都必须是先把所有的绘图对象重绘一次。这个其实并没有必要。一个优化方案是通过设置一个标记,在绘图循环中(一般在复杂绘图中都把绘图对象保存在一个数组或链表中),当这个标记为TRUE时,就停止绘图,当这个标记为FALSE则不影响绘图。在处理WM_MOUSEWHEEL消息是,先设置这个标记为TRUE,然后发送一个重绘消息,设置标记为FALSE进行重绘。然后在绘图循环时先判断这个标记是否TRUE,为TRUE则退出绘图,然后截取鼠标消息,优先WM_MOUSEWHEEL消息,大致代码如下:
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。一个老生常谈的问题,如何防止C#绘图时的闪烁
[问题点数:50分,结帖人apolloshu]
本版专家分:21
结帖率 100%
CSDN今日推荐
本版专家分:2326
2003年1月 PowerBuilder大版内专家分月排行榜第一
2002年12月 PowerBuilder大版内专家分月排行榜第二
2003年3月 PowerBuilder大版内专家分月排行榜第三
本版专家分:60266
2003年9月 总版技术专家分月排行榜第三2003年8月 总版技术专家分月排行榜第三
2003年8月 .NET技术大版内专家分月排行榜第一
2003年9月 .NET技术大版内专家分月排行榜第二
2003年7月 .NET技术大版内专家分月排行榜第三
本版专家分:1986
本版专家分:2673
本版专家分:21
结帖率 100%
本版专家分:80
本版专家分:21
结帖率 100%
本版专家分:60266
2003年9月 总版技术专家分月排行榜第三2003年8月 总版技术专家分月排行榜第三
2003年8月 .NET技术大版内专家分月排行榜第一
2003年9月 .NET技术大版内专家分月排行榜第二
2003年7月 .NET技术大版内专家分月排行榜第三
本版专家分:2957
本版专家分:1228
本版专家分:559
结帖率 98.8%
本版专家分:1228
本版专家分:1408
本版专家分:1424
本版专家分:21
结帖率 100%
本版专家分:255
本版专家分:21
结帖率 100%
匿名用户不能发表回复!|
CSDN今日推荐在使用vc开发图形相关的应用程序时,常常需要使用MFC的CDC类直接把图形画在窗口上。这通常是通过响应windows的WM_PAINT消息实现的。如果要画的图形比较复杂,或者比较大,那么画图过程可能会造成窗口的闪烁。当窗口调整大小时,这种闪烁由为明显。
解决窗口闪烁问题的有效办法就是使用内存DC,也称为缓冲DC。在内存中准备一个和窗口DC相同属性的DC,在这个内存DC上执行画图操作。完成画图以后,把画图输出的内容整体复制到目标窗口DC上。因为画图操作不在窗口DC上进行,所以在画图的过程中窗口可以保持原来的内容。当画好的内容被复制到窗口DC时,因为复制操作执行的非常快,所以用户感觉窗口仿佛被立刻被画好,从而消除了从旧画面到白板再到新画面的闪烁现象。
生成内存DC主要用到以下四个函数:
CreateCompatibleDC(CDC* pDC )。CDC类的成员函数,用于创建一个和pDC指向的DC兼容的内存DC。
CreateDiscardableBITmap( CDC* pDC, int nWidth, int nHeight)。CBitmap类的成员函数,用于按指定尺寸创建一个和pDC指向的DC兼容的位图。
SelectObject(CBitmap * pBitmap)。CDC类的成员函数,执行以后,所以在该DC上的图像输出都将被画到pBitmap指向的位图上。
BOOL BitBlt (int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop )。CDC类的成员函数,用于从源DC(pSrcDC)复制一个矩形的图象到当前DC中。
对于一个窗口,我们可以用下面的代码来创建内存DC,在内存DC上输出,并最终复制到窗口DC上。
void PaintWnd(CWnd * pWnd)...{
CDC * pWndDC = pWnd-&GetWindowDC();
CRect WndRect = pWnd-&GetWindowRect();
CDC MemDC;
CBitMap MemB
MemDC.CreateCompatibleDC(pWndDC);
利用屏幕DC创建内存DC
MemBitmap.CreateCompatibleBitmap(
利用屏幕DC创建兼容的位图
WndRect.Width(),
WndRect.Height());
MemDC.SelectObject(&MemBitmap);
// 让内存DC输出到位图
// 使用MemDC画图
// 。。。。。。
pWndDC-&BitBlt(
// 从内存DC复制到窗口DC
WndRect.Width(),
WndRect.Height(),
SRCCOPY);}
当然,实际的情况下,我们需要考虑的更多,因为内存DC、位图的创建都可能会失败。为了简化代码,笔者定义了一个类CMemoryDC,包装了内存DC创建过程中的出错处理,内存DC的事后清理等操作,并自动复制内存DC的内容到目标DC上。声明CMemoryDC类的头文件MemoryDC.h如下:
#pragma once#include "Afxwin.h" class CMemoryDC...{public:
CMemoryDC(CDC *dc, RECT * rect,bool autoRender = false);
~CMemoryDC(void);
bool IsOK();
void Render(CDC * p_objectDC = NULL);
CDC* GetMemoryDC();
operator CDC * ();private:
bool m_bAutoR
CRect m_DCR
CDC* m_pOriginalDC;
CDC m_MemoryDC;
CBitmap m_MemoryB};
类的实现文件CMemoryDC.cpp如下:
#include ".MemoryDC.h" CMemoryDC::CMemoryDC(CDC *dc, RECT * rect, bool autoRender)...{
m_bAutoRender = autoR
m_pOriginalDC =
if (dc==NULL || rect==NULL)
if (!m_MemoryDC.CreateCompatibleDC(dc))
m_DCRect.SetRect(rect-&left, rect-&top, rect-&right, rect-&bottom);
if (!m_MemoryBmp.CreateCompatibleBitmap(dc, m_DCRect.Width(), m_DCRect.Height()))
m_MemoryDC.SelectObject(m_MemoryBmp);} CMemoryDC::~CMemoryDC(void)...{
if (m_bAutoRender)
if (m_MemoryDC.m_hDC!=NULL)
m_MemoryDC.DeleteDC();
if (m_MemoryBmp.m_hObject!=NULL)
m_MemoryBmp.DeleteObject();} bool CMemoryDC::IsOK()...{
return m_MemoryDC.m_hDC!=NULL && m_MemoryBmp.m_hObject != NULL; }void CMemoryDC::Render(CDC * p_objectDC)...{
if (!IsOK())
CDC * pDC = (p_objectDC==NULL ? m_pOriginalDC : p_objectDC);
CSize Size = m_MemoryDC.GetViewportExt() ;
pDC-&BitBlt(
m_DCRect.left,
m_DCRect.top,
m_DCRect.Width(),
m_DCRect.Height(),
&m_MemoryDC,
SRCCOPY);}CDC* CMemoryDC::GetMemoryDC()...{
return & m_MemoryDC;}CMemoryDC::operator CDC * ()...{
return & m_MemoryDC;}
使用这个类可以大大简化内存DC的创建操作。如果我们在窗口消息WM_PAINT的响应函数中使用内存DC,只要用如下这样简便的代码便可实现:
CRect RGetClientRect(Rect);CPaintDC dc(this); // device context for painting
CMemoryDC MemDC(&dc, Rect, true);
if (MemDC.IsOK())
// 使用MemDC画窗口}
// MemDC析构时会自动把图像复制到dc,无需其它操作
使用CMemoryDC创建内存DC防止窗口闪烁,编程的代码和不使用内存DC时相比,数量和复杂性几乎没有增加。
没有更多推荐了,你的IE浏览器版本过低,为了提升体验,
建议升级到IE10以上或使用Chrome、搜狗等浏览器!
首先,我和你说下双缓冲技术双缓冲是将图片在显示到DC前,现在要内存建一个DC,也就是用于存储这张图片的内存区,然后在将这部分update到你要显示的地方这样,可以防止画面抖动很大(虽然有时候你不这样做,也会发现没什么差别,呵呵)这样和你说吧,如果要实现你要的效果,你必须用指针访问内存比如,把程序声明成unsafe的,然后按照上面的操作进行因为C#是快速开发,很多图形缩放功能,效果并不理想,比如,一个BItMap吧,假设不考虑其他属性,图片大小是100*100,如果你想在一个大小为200*200的PictureBox上添满,你只需要把属性改下,就可以了,其他的工作都由编译器帮你做了,把一张图片,进行缩放,保存为另一张,也是这样,你无法对他进行更细的操作所以,如果要实现你的要求,你必须要自己来进行处理内存部分这样实现起来有点麻烦,呵呵不过你只能这样有问题可以问我

我要回帖

更多关于 mfc 内存绘图 的文章

 

随机推荐