GDI双缓冲实现与GDI+双缓冲实现

合集下载

GDI+ 如何使用双缓冲绘制图像

GDI+ 如何使用双缓冲绘制图像

早前曾为此问题在CSDN发帖求助(GDI+ 如何使用双缓冲绘制图像),得到了一个GDI+下较可行的方法,虽然绘制效果比直接绘制要好一些,不过还不能跟GDI的双缓冲方式比肩。

现在,我终于找到了一个理想的实现方式,效果与GDI的实现不相上下,代码如下:/*C++ code*/RECT rc;GetClientRect(g_hwnd,&rc);Bitmap bmp(int(rc.right),int(rc.bottom));Graphics bmpGraphics(&bmp);bmpGraphics.SetSmoothingMode(SmoothingModeAntiAlias);/*Drawing on bitmap*/SolidBrush bkBrush(Color(0,0,0));bmpGraphics.FillRectangle(&bkBrush,0,0,rc.right,rc.bottom);/*Drawing on DC*/Graphics graphics(hdc);/*Important! Create a CacheBitmap object for quick drawing*/CachedBitmap cachedBmp(&bmp,&graphics);graphics.DrawCachedBitmap(&cachedBmp,0,0);以上的绘制代码最区别于网络上其他GDI+实现的一处就是,在最后添加了一个CacheBitmap对象用于快速绘制。

CacheBitmap是一个包含了bmp全部象素,并且针对graphics所关联的DC做过特别优化的位图对象。

这点可以从其构造参数上看到。

关于双缓冲的实现还有一点十分关键,虽然它不属于双缓冲实现的核心。

如果绘制需要经常的重绘背景,则需要自己拦截WM_ERASEBKGND消息,并在处理函数中什么也不做,即此消息发生时不重画背景,背景的重画在WM_PAINT中全权控制。

如何实现双缓冲

如何实现双缓冲

如何实现双缓冲双缓冲即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,这样能大大加快绘图的速度。

双缓冲实现过程如下:1、在内存中创建与画布一致的缓冲区2、在缓冲区画图3、将缓冲区位图拷贝到当前画布上4、释放内存缓冲区(1)在内存中创建与画布一致的缓冲区CDC dc;//这是窗口的DC,假设已加载好CDC MemDC; //创建内存中的一个临时dc- MemDC, MemDC用来向窗口绘图的“草稿”//随后建立与屏幕显示兼容的内存显示设备MemDC.CreateCompatibleDC(&dc); //这时还不能绘图,因为没有地方画 ^_^//创建的临时空白bitmap作为“画布”,至于位图的大小,可以用窗口的大小CBitmap MemBitmap;MemBitmap.CreateCompatibleBitmap(&dc,nWidth,nHeight);//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); //将上面创建的临时“画布”MemBitmap与MemDC连接,注意此处的MemBitmap为一个空白临时画布,可以在这个空白画布上自绘图,也可以在这个画布上加载图片//先用背景色将位图清除干净,这里我用的是白色作为背景//你也可以用自己应该用的颜色MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));(2)在缓冲区画图MemDC.MoveTo(……);MemDC.LineTo(……);(2)'在第(2)步中,如果不是自绘图,而是加载一个位图,则需要再定义一个临时dc- MemDC2,用来将位图加载到上面建立的空白画布MemDC中CBitmap p1;//这是要画的位图,假设已加载好CDC MemDC2;MemDC2.CreateCompatibleDC(&dc);MemDC2.SelectObject(&p1);// MemDC2与图片链接//在这里,p1保存的是要加载到临时空白画布上的图片,MemDC2是与p1链接的dc(3)将缓冲区位图拷贝到当前画布(屏幕)上dc.BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY);(3)’如果是位图的话首先,将与MemDC2链接的位图p1拷贝到临时空白画布MemDC中MemDC.BitBlt(x,y,width,height,& MemDC2,0,0,SRCCOPY); //向草稿绘制第一张图片,x,y,width,height请自行设置其次,将草稿绘制到屏幕上dc.BitBlt(0,0,width,height,&MemDC,0,0,SRCCOPY);(4)释放内存缓冲区//绘图完成后的清理MemBitmap.DeleteObject();MemDC.DeleteDC();MemDC2.DeleteDC();下面是一个不使用和使用双缓存的例子使用双缓存//CPoint ptCenter;//CRect rect, ellipseRect;//GetClientRect(&rect); //获得窗口客户区的大小//ptCenter = rect.CenterPoint(); //获得矩形的中心点,目的是为了确定后面同心圆图像的圆心//CDC dcMem; // 创建用于缓冲作图的内存DC对象dcMem//CBitmap bmp; // 创建内存中存放临时图像的位图对象bmp//dcMem.CreateCompatibleDC(pDC); // 依附窗口DC(窗口对象为pDC),创建兼容内存DC(就是创建一个内存DC,所有图形先画在这上面)//bmp.CreateCompatibleBitmap(&dcMem, rect.Width(), rect.Height());// 在兼容内存DC上,创建兼容位图//dcMem.SelectObject(&bmp); // 将位图选入内存DC//dcMem.FillSolidRect(rect, pDC->GetBkColor());// 按照原有背景色填充客户区,否则会成为黑色,同时也使内存DC的背景色保持一致//// 绘图操作//for (int i = 60; i > 0; --i)//{// ellipseRect.SetRect(ptCenter, ptCenter);// ellipseRect.InflateRect(i * 5, i * 5);// dcMem.Ellipse(ellipseRect); // 在内存DC上绘图,做同心圆图像//}//pDC->BitBlt(0, 0, rect.Width(), rect.Height(),// &dcMem, 0, 0, SRCCOPY); // 将内存DC上的图像复制到前台pDC,即实际屏幕对象pDC//dcMem.DeleteDC(); // 删除内存DC//bmp.DeleteObject(); // 删除内存位图不使用双缓存CPoint ptCenter;CRect rect,ellipseRect;GetClientRect(&rect);ptCenter = rect.CenterPoint();for(int i=60;i>0;i--){ellipseRect.SetRect(ptCenter,ptCenter);ellipseRect.InflateRect(i*5,i*5);pDC->Ellipse(ellipseRect);}下面的例子是加载两幅图片CBitmap p1,p2;//这是要画的位图,假设已加载好CDC dc;//这是窗口的DC,假设已加载好//创建两个临时dc,dc1为向窗口绘图的“草稿”,dc2为与源位图连接的dc(实际上dc2也可以用别的方法代替,这只是我的癖好)CDC dc1,dc2;dc1.CreateCompatibleDC(&DC);dc2.CreateCompatibleDC(&DC);//创建一个临时bitmap作为“画布”,与dc1连接CBitmap bm;CBitmap *Oldbm1,Oldbm2bm.CreateCompatibleBitmap(pDC,width,height); //长度宽度设置成与绘图面积一样大dc1.SelectObject(&bm);dc2.SelectObject(&p1);//dc2与第一张图片链接dc1.BitBlt(x,y, width,height,&dc2,0,0,SRCCOPY); //向草稿绘制第一张图片,x,y,width,height请自行设置dc2.SelectObject(&p2);//dc2与第一张图片链接dc1.BitBlt(x,y, width,height,&dc2,0,0,SRCCOPY); //向草稿绘制第二张图片//将草稿转移至窗口dc.BitBlt(0,0, width,height,&dc1,0,0,SRCCOPY);//清理工作...。

+MFC+GDI双缓冲避免图形闪烁

+MFC+GDI双缓冲避免图形闪烁

// TODO: Add your specialized creation code here SetTimer(1,10,NULL); return 0; } 利用定时器直接进行 10 毫秒的屏幕刷新,这样效果会出现不停的闪烁的情况. 解决方法利用双缓冲,首先触发 WM_ERASEBKGND,然后修改返回 TRUE; 定义变量: CBitmap *m_pBitmapOldBackground ; CBitmap m_bitmapBackground ; CDC m_dcBackground; //绘制背景 if(m_dcBackground.GetSafeHdc()== NULL|| (m_bitmapBackground.m_h Object == NULL)) {
MemDC.CreateCompatibleDC(NULL); //这时还不能绘图,因为没有地方画 ^_^ //下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的 大小 MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight); //将位图选入到内存显示设备中 //只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上 CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); //先用背景色将位图清除干净,这里我用的是白色作为背景 //你也可以用自己应该用的颜色 MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255)); //绘图 MemDC.MoveTo(……); MemDC.LineTo(……);
} 说到这里可能又有人要说了 , 为什么一个简单图形看起来没有复杂图形那么闪呢? 这是因为复杂图形占的面积大,重画时造成的反差比较大,所以感觉上要闪得厉 害一些,但是闪烁频率要低。 那为什么动画的重画频率高,而看起来却不闪?这里,我就要再次强调了,闪烁 是什么?闪烁就是反差,反差越大,闪烁越厉害。因为动画的连续两个帧之间的 差异很小所以看起来不闪 。 如果不信 , 可以在动画的每一帧中间加一张纯白的帧 , 不闪才怪呢。 2、如何避免闪烁 在知道图形显示闪烁的原因之后,对症下药就好办了。首先当然是去掉 MFC 提 供的背景绘制过程了。实现的方法很多, * 可以在窗口形成时给窗口的注册类的背景刷付 NULL * 也可以在形成以后修改背景 static CBrush brush(RGB(255,0,0)); SetClassLong(this->m_hWnd,GCL_HBRBACKGROUND,(LONG)(HBRU SH)brush); * 要简单也可以重载 OnEraseBkgnd(CDC* pDC)直接返回 TRUE. 这样背景没有了,结果图形显示的确不闪了,但是显示也象前面所说的一样,变 得一团乱。怎么办?这就要用到双缓存的方法了。双缓冲就是除了在屏幕上有图 形进行显示以外,在内存中也有图形在绘制。我们可以把要显示的图形先在内存 中绘制好 , 然后再一次性的将内存中的图形按照一个点一个点地覆盖到屏幕上去 (这个过程非常快,因为是非常规整的内存拷贝)。这样在内存中绘图时,随便 用什么反差大的背景色进行清除都不会闪,因为看不见。当贴到屏幕上时,因为 内存中最终的图形与屏幕显示图形差别很小 (如果没有运动 , 当然就没有差别) , 这样看起来就不会闪。 3、如何实现双缓冲 首先给出实现的程序,然后再解释,同样是在 OnDraw(CDC *pDC)中: CDC MemDC; //首先定义一个显示设备对象 CBitmap MemBitmap;//定义一个位图对象 //随后建立与屏幕显示兼容的内存显示设备

gdi+原理

gdi+原理

GDI (Graphics Device Interface) 是一种图形设备接口,它提供了一组函数和数据结构,用于在计算机屏幕上绘制图形和文本。

GDI 的工作原理可以简单概括如下:
1. 设备无关性:GDI 提供了一套抽象的图形操作接口,使得应用程序不需要关心底层硬件的差异。

它可以在不同类型的图形设备(如显示器、打印机)上执行相同的绘图操作。

2. 句柄管理:GDI 使用句柄来标识各种图形对象,例如窗口、画刷、字体等。

应用程序通过创建和使用这些句柄来操作图形对象。

GDI 负责管理这些句柄,包括分配、释放和查询对象。

3. 绘图操作:GDI 提供了一系列函数,用于在设备上进行绘图操作。

这些函数包括绘制线条、填充区域、绘制文本等。

应用程序可以根据需要调用这些函数来实现所需的图形效果。

4. 坐标系统:GDI 使用一个坐标系统来确定图形和文本的位置。

通常,坐标原点位于设备的左上角,水平向右为正,垂直向下为正。

应用程序可以使用坐标系统来定位和变换图形对象。

5. 双缓冲技术:为了避免绘图时的闪烁和不流畅现象,GDI 使用双缓冲技术。

在内存中创建一个临时的图像缓冲区,所有的绘图操作先在缓冲区中进行,然后再将整个缓冲区一次性地绘制到屏幕上,从而实现平滑的图形显示。

总之,GDI 是一个用于绘制图形和文本的图形设备接口,它提供了设备无关性、句柄管理、绘图操作、坐标系统和双缓冲等特性,使得应用程序可以方便地操作图形对象并实现所需的图形效果。

1。

VC中的GDI双缓冲绘图

VC中的GDI双缓冲绘图

CBitmap* m_pOldBmp;
ATL程序中,可在atlgdi.h找到基于ATL程序的内存DC:
class CMemoryDC : public CDC { public: // Data members HDC m_hDCOriginal; RECT m_rcPaint; CBitmap m_bmp; HBITMAP m_hBmpOld; // Constructor/destructor CMemoryDC(HDC hDC, RECT& rcPaint) : m_hDCOriginal(hDC), m_hBmpOld(NULL) {


双缓冲绘图原理

普通绘图操作
物理DC绘图 操作 屏幕

双缓冲绘图操作
物理DC绘图 操作 屏幕
内存DC
实现过程

1. 2. 3. 4. 5. 6.
创建兼容DC 创建兼容位图 用兼容DC关联兼容位图 使用兼容DC绘图 将兼容DC拷贝到物理DC上 回收兼容位图和兼容DC,防止资源泄露
实现代码
CPaintDC dc(this);
// 绘图区域 CRect rectClient; GetClientRect(&rectClient);
// 创建兼容DC
CDC dcMem; dcMem.CreateCompatibleDC(&dc); // 创建兼容位图,使兼容DC与之关联,否则兼容DC则是一个1*1的单色位图 CBitmap bitmap;
SetViewportOrg(-m_rcPaint.left, -m_rcPaint.top);
} ~CMemoryDC() {
::BitBlt(m_hDCOriginal, m_rcPaint.left, m_rcPaint.top, m_rcPaint.right - m_rcPaint.left, m_rcPaint.bottom m_rcPaint.top, m_hDC, m_rcPaint.left, m_rcPaint.top, SRCCOPY); SelectBitmap(m_hBmpOld);

GDI实现双缓冲

GDI实现双缓冲
/* 保存窗口句柄与程序实例句柄到全局变量 */
main_window_handle = hwnd;
hinstance_app = hinstance;
/* global_hdc为当前窗口的hdc buffer_hdc为后备缓冲 */
/* 初始化 */
global_hdc = GetDC(main_window_handle);
在上篇文章中将我要用C语言重新写一个俄罗斯方块,使用的是GDI的绘图模式(目前正在移植到DX上去,想添加一些更好友好的动画)。数据与动画分离,动画的帧率保持在30左右。但是绘图的时候画面出现了强烈的闪动。
排查了一下原因,不是由于电脑性能的原因(如果画几个线就闪的话那就糟了),而是由于采用的动画方式导致的。我采用的是擦除,绘制,擦除,绘制的模式。没有使用双缓冲。要解决画面闪烁,就要使用到双缓冲。
if(global_hdc)
ReleaseDC(main_window_handle,global_hdc);
if(buffer_hdc)
DeleteDC(buffer_hdc);
if(bmp)
DeleteObject(bmp);
/* 程序返回 */
return messages.wParam;
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
/* 窗口过程 */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
void Clear_Window(HDC hdc);
HWND main_window_handle = NULL; //保存窗口句柄的全局变量

C# WinForm利用GDI+的双缓冲技术来提高绘图效率

C# WinForm利用GDI+的双缓冲技术来提高绘图效率

C# WinForm利用GDI+的双缓冲技术来提高绘图效率前言进入.NET时代,Windows的绘图技术也从GDI升级到了GDI+,从名字就能知道GDI+是对以前传统GDI 绘图技术的一次升级,不过在微软几乎把所有的新技术都冠之.NET的情况下,GDI+竟然不叫做,还真让我感到有点意外了。

:)GDI+在一种与设备无关的环境下提供了一套统一的绘图编程模型,极大的提高了Windows绘图编程的方便性,我们再也不用创建什么各种各样复杂的设备环境了,说实话,我现在想起来都头疼。

题归正传,关于如何进行GDI+的基本编程,我不能过多的加以描述,如果有对此概念还不太清楚的朋友,建议先去了解一下相关的资料,我们在这里主要讨论的是一种提高绘图效率(主要是动画效率)的双缓冲技术在GDI+中的应用和实现。

实现目的为了能清楚的对比应用双缓冲技术前后的效果,我编写了一段程序来进行测试。

首先,我创建了一个普通的Windows Application,在主Form中,我放置了一个定时器:timer1,然后将它的Interval属性设置为10,然后在Form上放置两个按纽,分别用来控制定时器的开启和关闭,最后,我还放置了一个label控件,用来显示绘图的帧数。

测试程序在timer1的timer1_Tick事件中,我写下了如下的代码(其中flag是一个bool型标志变量):DateTime t1 = DateTime.Now;Graphics g = this.CreateGraphics();if(flag){brush = new LinearGradientBrush(new PointF(0.0f, 0.0f),new PointF(700.0f, 300.0f), Color.Red, Color.Blue);flag = false;}else{brush = new LinearGradientBrush(new PointF(0.0f, 0.0f),new PointF(700.0f, 300.0f), Color.Blue, Color.Red);flag = true;}for(int j = 0; j < 60; j ++){for(int i = 0; i < 60; i++){g.FillEllipse(brush, i * 10, j * 10, 10, 10);}}DateTime t2 = DateTime.Now;TimeSpan sp = t2 - t1;float per = 1000 / liseconds;bel1.Text = "速度:" + per.ToString() + "帧/秒";运行后,我点击“开始”按纽,效果如下图所示:应用双缓冲以前的效果图(帧数:5帧/秒)正如大家所看到的,我在程序中使用循环画了几百个圆形,然后在每次的定时器脉冲事件中使用不同方向的线性渐变来对它们进行填充,形成了一个动画效果。

在GDI+中使用双缓存

在GDI+中使用双缓存

在GDI+中使用双缓存
申晓
【期刊名称】《电脑编程技巧与维护》
【年(卷),期】2004(000)006
【摘要】制作简单的动画效果时,帧速率是一个很重要的指标。

每秒帧数越高,画面看上去越平滑自然,即使前景和背景的色彩反差比较大时,也不会觉得闪烁。

实现动画的原理很简单,就是让相邻的两帧之间有些不同,然后高速播放,这样就给人一种连贯性的感觉。

比如本例程中,是制作一个模拟时钟。

秒针、分针和时针的位置,每时每刻都有微小的变化,那么不断地刷新画面,反映出的结果就是表针在慢慢地走动。

【总页数】2页(P15,32)
【作者】申晓
【作者单位】无
【正文语种】中文
【中图分类】TP391.41
【相关文献】
1.在GDI+中利用双缓存技术实现橡皮筋效果 [J], 张卫华
2.在Visual C++6.0中使用GDI+的双缓冲技术绘图 [J], 唐琳;黄猛
3.Visual C++中双缓存滚动视图类开发及使用 [J], 钱昌松;刘志刚
4.使用双缓存来解决GDI下的闪烁问题 [J], 韩丽娜;石昊苏
5.GDI+与OpenCV在编程中混合使用的研究 [J], 吴东;谢国波;苏本卉
因版权原因,仅展示原文概要,查看原文内容请购买。

双缓冲

双缓冲
三、双缓冲图形刷新技术的原理
双缓冲图形刷新技术顾名思义是采用双缓存实现的。传统的绘图方式实际上是一种单缓冲。在windows中每一种设备都在内存中有一个设备描述表与其对应,这个设备描述表实际上就是一个内存缓冲区。传统的绘图中我们是将图形绘制在设备描述表缓冲区中,然后由gdi自动的将设备描述表中的图像拷贝到显存中进行显示。这样一个自动的拷贝过程屏蔽了传统的绘图方式是单缓冲的实质,使我们感觉到我们是在直接操纵显存一样。双缓冲图形刷新技术在内存中有两片缓存,除了设备描述表以外还有一个需要手动建立的与设备描述表缓冲区(前端缓冲区)相兼容的后备缓冲区。绘图过程中,首先将图形绘制在后备缓冲区中,然后在手动的将后备缓冲区中的图像拷贝到前端缓冲区中,再由gdi自动将前端缓冲区中的图像拷贝到显存完成图形的显示过程。
//先用背景色将位图清除干净,这里我用的是白色作为背景
//你也可以用自己应该用的颜色
MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));
//绘图
MemDC.MoveTo(……);
MemDC.LineTo(……);
//将后备缓冲区中的图形拷贝到前端缓冲区
1、编写一个刷新速度很慢的应用程序,可以设计为通过点击鼠标来进行屏幕刷新。通过该试验可以发现即使屏幕的刷新速度很慢,但是在每次刷新的时候仍然存在屏幕的问题,只是闪烁不是很明显。
2、编写一个刷新速度很快的应用程序,并在程序中应用双缓冲图形刷新技术。通过该试验可以发现虽然屏幕刷新速度很快,但是采用了双缓冲图新刷新技术以后,屏幕不存在闪烁。
CBitmap MemBitmap;
//建立与屏幕设备描述表(前端缓冲区)兼容的内存设备描述表句柄(后备缓冲区)

使用双缓存来解决GDI下的闪烁问题

使用双缓存来解决GDI下的闪烁问题

。 引 言
在 进 行 图 形 图 像 处 理 的 软 件 中 , 般 的 图形 处 理 程 序 需 一 要 大 量 的绘 图操 作 , 要 解 决绘 图 的 效 率 和 效 果 问题 : 者 表 首 前 现 在 性 能 方 面 , 否 有 延 迟 , 个 小 小 的 交 互 操 作 是 否 要 等 上 是 一 几秒才 能看到 结果 ;后者表现 在软件 中 的图像是否 闪烁? 比 如 , O D a 中 加 入 如 下 代 码 就 可 看 到 闪烁 。 在 nr w0
维普资讯
第 2 卷 第 1 期 7 7
VO .ቤተ መጻሕፍቲ ባይዱ7 12
计 算 机 工 程 与 设计
Co u e n ie r ga d De in mp trE gn e i n sg n
20 年 9 06 月
S pt 0 6 e .2 0
N O. 7 1
摘 要 : 图形 图 像 处 理 过 程 中 , 在 当显 示 绘 制 的 图像 时 , 时 会 出现 闪 烁 的 情 况 。本 丈从 窗 口 、 口 、 有 视 坐标 系统 的 基 本 概 念 和 关 系 出 发 , 要 讲 解 了如 何 使 用 双 缓 存 来 解 决 GD 下 的 闪 烁 问题 此 方 法 已经 应 用 于 项 目地 质 资料 解 释 系统 中对 井 曲 线 的 主 I
De l g wi ik r r b e a o t a i t f c e o lm b u n hl p GD1 t o b eb fe i g h d u l u r wi n
HAN — a_ S o S Li I HIHa —U n .
(.Colg f nomainS in e n eh oo y 1 l eo Ifr t ce c dT c n lg ,Not s Unv ri ,Xi n7 0 6 ,Chn ; 2 e o a r Wet ies y h t 10 9 a ia .De at n f pr me t o

C#使用BufferedGraphics实现GDI+双缓冲绘图

C#使用BufferedGraphics实现GDI+双缓冲绘图

使用双缓冲的图形可以减少或消除重绘显示图面时产生的闪烁。

使用双缓冲时,更新的图形首先被绘制到内存的缓冲区中,然后,此缓冲区的内容被迅速写入某些或所有显示的图面中。

显示图形的重写相对简短,这通常可以减少或消除有时在更新图形时出现的闪烁。

使用C# GDI+绘图,实现双缓冲绘图有几种方法,在这篇文章中,将介绍其中的一种——使用BufferedGraphics实现GDI+双缓冲绘图。

下面的代码示例演示如何使用BufferedGraphics对象绘制以下图形,这些图形使用几种类型的缓冲实现。

单击窗体将启动或停止一个计时器,该计时器将引起绘制更新。

绘制更新使您可以观察双缓冲的效果。

右击窗体将循环使用下列绘制模式:∙对于Form,直接绘制到Handle。

∙对使用OptimizedDoubleBuffer控件样式的OnPaint方法进行重写,以进行绘制∙对于不使用OptimizedDoubleBuffer控件样式的窗体方法,重写OnPaint方法以进行绘制。

在每种模式下都将绘制文本,以标识当前模式并描述按下每个鼠标按钮时发生的行为。

using System;using ponentModel;using System.Drawing;using System.Windows.Forms;namespace BufferingExample{public class BufferingExample : Form{private BufferedGraphicsContext context;private BufferedGraphics grafx;private byte bufferingMode;private string[] bufferingModeStrings ={ "Draw to Form without OptimizedDoubleBufferring control style","Draw to Form using OptimizedDoubleBuffering control style","Draw to HDC for form" };private System.Windows.Forms.Timer timer1;private byte count;public BufferingExample() : base(){// Configure the Form for this example.this.Text = "User double buffering";this.MouseDown += newMouseEventHandler(this.MouseDownHandler);this.Resize += new EventHandler(this.OnResize);this.SetStyle( ControlStyles.AllPaintingInWmPaint | erPaint, true );// Configure a timer to draw graphics updates.timer1 = new System.Windows.Forms.Timer();timer1.Interval = 200;timer1.Tick += new EventHandler(this.OnTimer);bufferingMode = 2;count = 0;// Retrieves the BufferedGraphicsContext for the// current application domain.context = BufferedGraphicsManager.Current;// Sets the maximum size for the primary graphics buffer// of the buffered graphics context for the application// domain. Any allocation requests for a buffer larger// than this will create a temporary buffered graphics// context to host the graphics buffer.context.MaximumBuffer = new Size(this.Width+1,this.Height+1);// Allocates a graphics buffer the size of this form// using the pixel format of the Graphics created by// the Form.CreateGraphics() method, which returns a// Graphics object that matches the pixel format of the form.grafx = context.Allocate(this.CreateGraphics(),new Rectangle( 0, 0, this.Width, this.Height ));// Draw the first frame to the buffer.DrawToBuffer(grafx.Graphics);}private void MouseDownHandler(object sender, MouseEventArgs e){if( e.Button == MouseButtons.Right ){// Cycle the buffering mode.if( ++bufferingMode > 2 )bufferingMode = 0;// If the previous buffering mode used// the OptimizedDoubleBuffering ControlStyle,// disable the control style.if( bufferingMode == 1 )this.SetStyle( ControlStyles.OptimizedDoubleBuffer, true );// If the current buffering mode uses// the OptimizedDoubleBuffering ControlStyle,// enabke the control style.if( bufferingMode == 2 )this.SetStyle( ControlStyles.OptimizedDoubleBuffer, false );// Cause the background to be cleared and redraw.count = 6;DrawToBuffer(grafx.Graphics);this.Refresh();}else{// Toggle whether the redraw timer is active.if( timer1.Enabled )timer1.Stop();elsetimer1.Start();}}private void OnTimer(object sender, EventArgs e){// Draw randomly positioned ellipses to the buffer.DrawToBuffer(grafx.Graphics);// If in bufferingMode 2, draw to the form's HDC.if( bufferingMode == 2 )// Render the graphics buffer to the form's HDC.grafx.Render(Graphics.FromHwnd(this.Handle));// If in bufferingMode 0 or 1, draw in the paint method.elsethis.Refresh();}private void OnResize(object sender, EventArgs e){// Re-create the graphics buffer for a new window size.context.MaximumBuffer = new Size(this.Width+1,this.Height+1);if( grafx != null ){grafx.Dispose();grafx = null;}grafx = context.Allocate(this.CreateGraphics(),new Rectangle( 0, 0, this.Width, this.Height ));// Cause the background to be cleared and redraw.count = 6;DrawToBuffer(grafx.Graphics);this.Refresh();}private void DrawToBuffer(Graphics g){// Clear the graphics buffer every five updates.if( ++count > 5 ){count = 0;grafx.Graphics.FillRectangle(Brushes.Black, 0, 0, this.Width, this.Height);}// Draw randomly positioned and colored ellipses.Random rnd = new Random();for( int i=0; i<20; i++ ){int px = rnd.Next(20,this.Width-40);int py = rnd.Next(20,this.Height-40);g.DrawEllipse(new Pen(Color.FromArgb(rnd.Next(0, 255),rnd.Next(0,255), rnd.Next(0,255)), 1),px, py, px+rnd.Next(0, this.Width-px-20), py+rnd.Next(0, this.Height-py-20));}// Draw information strings.g.DrawString("Buffering Mode:"+bufferingModeStrings[bufferingMode], new Font("Arial", 8), Brushes.White, 10, 10);g.DrawString("Right-click to cycle buffering mode", new Font("Arial", 8), Brushes.White, 10, 22);g.DrawString("Left-click to toggle timed display refresh", new Font("Arial", 8), Brushes.White, 10, 34);}protected override void OnPaint(PaintEventArgs e){grafx.Render(e.Graphics);}[STAThread]public static void Main(string[] args){Application.Run(new BufferingExample());}}}。

使用双缓存来解决GDI下的闪烁问题

使用双缓存来解决GDI下的闪烁问题

使用双缓存来解决GDI下的闪烁问题
韩丽娜;石昊苏
【期刊名称】《计算机工程与设计》
【年(卷),期】2006(27)17
【摘要】在图形图像处理过程中,当显示绘制的图像时,有时会出现闪烁的情况.本文从窗口、视口、坐标系统的基本概念和关系出发,主要讲解了如何使用双缓存来解决GDI下的闪烁问题.此方法已经应用于项目地质资料解释系统中对井曲线的修改和显示部分,实践证明,这种方法是可行的.
【总页数】3页(P3258-3260)
【作者】韩丽娜;石昊苏
【作者单位】西北大学,信息科学技术学院,陕西,西安,710069;咸阳师范学院,计算机科学系,陕西,咸阳,712100;西北政法学院,信息网络中心,陕西,西安,710063
【正文语种】中文
【中图分类】TP311.11
【相关文献】
1.在GDI+中使用双缓存 [J], 申晓
2.基于双缓存技术解决某模拟系统实时显示屏幕闪烁的方法 [J], 董燕;周燕明;崔卫兵
3.基于双缓存技术解决某模拟系统实时显示屏幕闪烁的方法 [J], 董燕;周燕明;崔卫兵
4.VC6.0下使用GDI+为应用程序添色彩 [J], 费之茵
5.基于双缓存技术解决某模拟系统实时显示屏幕闪烁的方法 [J], 董燕;周燕明;崔卫兵
因版权原因,仅展示原文概要,查看原文内容请购买。

mfc双缓冲

mfc双缓冲
一、屏幕闪烁的根本原因:
相邻两帧图像之间存在的巨大差异造成的,而windows gdi的图形刷新方式使得任何两帧图像之间都存在着巨大的差异,因为windows gdi在进行刷新之前都会首先将整个屏幕刷成白色,就相当于在电影胶片的相邻两帧之间都插入了一个白色的帧,这也就是为什么屏幕闪烁时总是看到一个隐约的白色窗口在闪烁而不是一个红色的窗口在闪烁。双缓冲图形刷新技术避免了windows gdi刷新的问题,其没有在连续的两帧之间插入白色的帧,从而解决了屏幕闪烁的问题。
三、示例代码
1、首先在OnDraw()或者OnPaint()中添加下列代码
//定义一个位图对象
CBitmap bitmap,MemBitmap;
CDC MemDC;
bitmap.LoadBitmap(IDB_BITMAP3);
BITMAP bmp;
bitmap.GetBi幕设备描述表(前端缓冲区)兼容的内存设备描述表句柄(后备缓冲区)
MemDC.CreateCompatibleDC(NULL);
//这时还不能绘图,因为没有位图的设备描述表是不能绘图的
//下面建立一个与屏幕设备描述表(或者内存设备描述表)兼容的位图
MemBitmap.CreateCompatibleBitmap(pDC,600,660);
2、添加WM_ERASEBKGND响应函数,并清除响应函数的生成代码在其中添加如下代码
BOOL OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//return CDialog::OnEraseBkgnd(pDC);
return FALSE;

C#使用Bitmap实现GDI+双缓冲绘图

C#使用Bitmap实现GDI+双缓冲绘图

下面是实现本示例的几个步骤:一、创建一个Windows程序项目,在项目里面创建一个窗口,命名为:FormBuffering,在窗口上添加另两个按钮,分别命名为:btnStart和btnStop。

二、复制下面的源码,覆盖自动生成的代码:using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;namespace ImageDoubleBuffer{public partial class FormBuffering : Form{private Bitmap _bufferImage;private int _count;private Timer _timer;public FormBuffering(){InitializeComponent();_bufferImage = new Bitmap(ClientSize.Width,ClientSize.Height);_timer = new Timer();_timer.Interval = 200;_timer.Tick += delegate(object sender, EventArgs e){_count++;if (_count > 6){_count = 0;}base.Invalidate();};btnStart.Click += delegate(object sender, EventArgs e) {_timer.Start();};btnStop.Click += delegate(object sender, EventArgs e) {_timer.Stop();_count = 0;};}///<summary>///当窗体改变大小时,重新初始化图片。

于双缓冲技术的GDI无闪烁绘图

于双缓冲技术的GDI无闪烁绘图


Flickerfree GDI + drawing based on double buffering
JIANG Jianguo , WEN Shaoying, ZHANG Ruinan
( School of Mathematies, Liaoning Normal University, Dalian Liaoning 116029 , China)
基于双缓冲技术的 GDI + 无闪烁绘图
江建国 ,温少营,张瑞楠
( 辽宁师范大学 数学学院, 辽宁 大连 116029 ) ( * 通信作者电子邮箱 jjgbox@ sina. com)
*
要: 图形闪烁是使用 GDI + 编写 Windows 窗体应用程序时经 常 遇 到的 一 个 问题。 在 深 入 分析 窗 体重 绘 模型 阐述了图形闪烁的本质原因。利用. NET框架 中 内 置 的 双 缓 冲 技术, 提出了 两 种 GDI + 无 闪烁 绘 图方 法。 以 基础上, 模拟时钟程序为例, 说明了这两种方法都非常简便且有效。 关键词: 双缓冲; 无闪烁绘图; 图形闪烁; GDI + ; . NET框架; 模拟时钟 中图分类号: TP391. 41 文献标志码: A
this. SetStyle( ControlStyles. OptimizedDoubleBuffer | ControlStyles. UserPaint | ControlStyles. AllPaintingInWmPaint, true) ;
向 Windows 窗体注册一个名为 MyPaintHandler 的 Paint 事件 处理程序, 将重绘窗体的代码添加到方法 MyPaintHandler 中:

利用双缓存技术解决GDI画图的刷新问题

利用双缓存技术解决GDI画图的刷新问题

利用双缓存技术提高GDI+的绘图效果摘要在进行图像处理的软件中,一般的图形处理程序需要大量的绘图操作,首要解决的就是绘图的效率和效果问题:前者表现在性能方面,是否有延迟,一个小小的交互操作是否要等上几秒才能看到结果;后者表现在重新绘制或刷新的过程中出现闪烁?本文主要介绍GDI+程序中引用双缓冲技术以解决重绘时出现的闪烁问题—提高绘图效果。

关键字:GDI+;双缓存;快速;缓存位图;效果引言在使用GDI+的实际的绘图中,绘图窗口内容或大小每改变一次,都要调用Paint事件进行重绘操作,该操作会使画面重新刷新一次以维持窗口正常显示。

这样的效率非常低,不仅达不到性能要求,而且还可能会出现闪烁的现象。

刷新过程中会导致所有图元重新绘制,而各个图元的重绘操作并不会导致Paint事件发生,因此窗口的每一次刷新只会调用Paint事件一次。

窗口刷新一次的过程中,每一个图元的重绘都会立即显示到窗口,因此整个窗口中,只要是图元所在的位置,都在刷新,而刷新的时间是有差别的,闪烁现象自然会出现。

所以说,此时导致窗口闪烁现象的关键因素并不在于Paint事件调用的次数多少,而在于各个图元的重绘。

根据以上分析可知,当图元数目不多时,窗口刷新的位置也不多,窗口闪烁效果并不严重;当图元数目较多时,绘图窗口进行重绘的图元数量增加,绘图窗口每一次刷新都会导致较多的图元重新绘制,窗口的较多位置都在刷新,闪烁现象自然就会越来越严重。

特别是图元比较大绘制时间比较长时,闪烁问题会更加严重,因为时间延迟会更长。

1、双缓存技术为了解决画图的效率问题,我们引进了双缓存技术,双缓冲技术早在GDI的程序开发中,就已经开始使用。

在普通的绘图模式下,图像处理程序是按照设计的顺序,将被绘制的元素一个接一个地在目标设备上进行绘制。

何谓“双缓冲”?它的基本原理就是:先在内存中开辟一块虚拟画布,然后将所有需要画的图形先画在这块“虚拟画布”上,最后在一次性将整块画布画到真正的窗体上。

GDI+双缓冲的实现方法

GDI+双缓冲的实现方法

一、 概述这段时间在研究GDI+双缓冲的实现方法,在网上花了很多时间都没有找到合适的示例,特别是针对VC6的。

后来通过对网上资料的分析,和对SDK/MFC的学习,实现了VC6下的GDI+双缓冲,把它写出来与大家分享,希望可以找到更好的实现方法。

GDI+的一个优点就是可以直接使用jpg图像,在这个示例中,我没有把图像文件放在资源中,而是动态读取,一是由于项目需求,图像数目是未知的;二是由于动态读文件效率低下,使用双缓冲更能体现出优势。

二、 分析在实现过程中,犯了一个错误,把读图像的方法放在了OnDraw之中,后来发现拖动滚动条闪烁的很严重,原因在于ScrollBar拖动时会产生消息激活OnDraw,这样的话,每拖动滚动条就读一次文件,重绘一次,效率当然低下了!我的实现方式是:更换图像后调用UpdateAllViews,内存DC的绘制都放在OnUpdate中操作,在内存绘制好后再在屏幕中贴图。

view sourceprint?1.// 贴上画布2.m_pOldBitmap = m_memDC.SelectObject(&m_memBitmap);3.m_memDC.FillSolidRect(0,0,2000,2000,RGB(100,100,100)); view sourceprint?01.// 贴图02.CString pStrFullPath = pDoc->m_pStrMapPath + pDoc->m_pStrMapName;ES_CONVERSION;04.LPWSTR wStr = A2W(pStrFullPath);05.Image img(wStr);06.pDoc->m_nMapWidth = img.GetWidth();07.pDoc->m_nMapHeight = img.GetHeight();08.Graphics g(m_memDC.GetSafeHdc());09.g.DrawImage(&img,0,0,img.GetWidth(),img.GetHeight()); view sourceprint?1.// 恢复2.m_memDC.SelectObject(m_pOldBitmap);三、截图图一 GDI+双缓冲效果四、结束语如果大家有更好的方法,请写出来分享。

双缓冲技术(基于GDI+实现)

双缓冲技术(基于GDI+实现)

双缓冲技术(基于GDI+实现)一、双缓冲技术双缓冲即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,这样能大大加快绘图的速度。

当数据量很大时,绘图可能需要几秒钟甚至更长的时间,而且有时还会出现闪烁现象,为了解决这些问题,可采用双缓冲技术来绘图。

双缓冲实现过程如下:1、在内存中创建与画布一致的缓冲区2、在缓冲区画图3、将缓冲区位图拷贝到当前画布上4、释放内存缓冲区在图形图象处理编程过程中,双缓冲是一种基本的技术。

我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。

解决这一问题的有效方法就是双缓冲技术。

因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。

当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。

于是我们就看到了闪烁现象。

我们会很自然的想到,避免背景色的填充是最直接的办法。

但是那样的话,窗体上会变的一团糟。

因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。

所以单纯的禁止背景重绘是不够的。

我们还要进行重新绘图,但要求速度很快,于是我们想到了使用BitBlt函数。

它可以支持图形块的复制,速度很快。

我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。

以上也就是双缓冲绘图的基本的思路。

二、基于GDI+实现双缓冲技术1.CPaintDC dc(this); // device context for painting2.Graphics gr(dc.m_hDC); // Graphics to paint1.Rect rGdi;2.gr.GetVisibleClipBounds(&rGdi); // The same as the clip rect3.4.//创建缓冲区5.Bitmap clBmp(rGdi.Width, rGdi.Height); // Mem bitmap6.Graphics* grPtr = Graphics::FromImage(&clBmp); // As memDC7.8.//利用grPtr在clBmp缓冲区绘图9.grPtr->DrawImage(m_PngMeter,clock_Rect);10.grPtr->TranslateTransform(Pcenter.X,Pcenter.Y);11.grPtr->RotateTransform(i);12.grPtr->TranslateTransform(-Pcenter.X,-Pcenter.Y);13.grPtr->DrawImage(m_PngArrow,picRect);14.grPtr->ResetTransform();15.16.//将clBmp缓冲区绘制到窗口17.gr.DrawImage(&clBmp, rGdi);<pre class="cpp" name="code"> delete grPtr;//注:使用完缓冲区后,一定要及时释放内才能,尤其是在OnPaint中,否则程序很快占满物理内存,崩溃!这里是在WM_PAINT消息里面处理的。

使用gdi在窗口上画出一个图片(UseGDItodrawapictureonthewindow)

使用gdi在窗口上画出一个图片(UseGDItodrawapictureonthewindow)

使用gdi在窗口上画出一个图片(Use GDI to draw a picture on thewindow)GDI双缓冲函数实现步骤PAINTSTRUCT PS;HDC HDC;/ /获取屏幕显示直流HDC = BeginPaint(HWND,和PS);/ /创建内存直流HDC hdcmem = CreateCompatibleDC(HDC);/ /创建一个BMP内存空间HBITMAP hBMP = CreateCompatibleBitmap(HDC,screen_width,screen_height);/ /将BMP内存空间分配给内存直流hgdiobj holdsel = SelectObject(hdcmem,hBMP);/ /这是使用者需要绘制的画面,全部往内存直流绘制矩形(hdcmem,0,0,screen_width,screen_height);DrawMenuButton(hdcmem);将内存的内容复制到屏幕显示直流/直流中,完成显示BitBlt(HDC,0,0,screen_width,screen_height,hdcmem,0,0,srccopy);/ /清除资源SelectObject(hdcmem,holdsel);DeleteDC(hdcmem);EndPaint(HWND,和PS);=========================================================== ===直流= GetDC(窗口句柄)memhdc = createcompitabledc(DC)SelectObject(memhdc,图片句柄)BitBlt(HDC,0,0100,24,memdc,0,0,srccopy)=========================================================== =========gdiploadimagefromfile载入PNG图片?1首先把位图载入:LoadImage(HBITMAP BMP = null,”D:/标志。

双缓冲的基本原理

双缓冲的基本原理

双缓冲的基本原理
双缓冲是一种图形显示技术,其基本原理是利用两个缓冲区来实现平滑的图形显示。

在传统的单缓冲模式下,图形的绘制是直接在屏幕上进行的。

这意味着绘制过程是可见的,并且可能会出现图像闪烁、图像残留等问题,特别是在动态图形的情况下。

而双缓冲技术通过使用两个缓冲区来解决这些问题。

其中一个缓冲区被称为前缓冲区,用于保存即将显示在屏幕上的图像;另一个缓冲区被称为后缓冲区,用于保存正在绘制或已经绘制完成但还未显示的图像。

绘制操作首先在后缓冲区进行,然后才将绘制完成的图像复制到前缓冲区,最后再将前缓冲区的图像显示在屏幕上。

这样,当图像绘制完成时,前缓冲区中的图像会一次性地显示在屏幕上,避免了直接在屏幕上进行绘制时可能出现的闪烁和残留问题。

双缓冲技术有效降低了图像绘制的可见性,提升了图形显示的平滑性和性能。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

GDI双缓冲实现与GDI+双缓冲实现
分类:C++ 2013-03-21 13:32 57人阅读评论(0) 收藏举报
我们看电视时,看到的屏幕称为OSD层,也就是说,只有在OSD层上显示图像我们才能看到。

现在,我需要创建一个虚拟的、看不见但是可以在上面画图(比如说画点、线)的OSD层,我称之为offscreen(后台缓冲区)。

这个offscreen存在于内存中,我们在上面画图,这个offscreen上面的东西可以显示在OSD层上,需要一个创建这个offscreen的函数,返回这个offscreen的句柄(整型指针)、宽度、高度、指向新建offscreen数据缓冲区的指针,该缓冲区是一个在函数外创建的offscreen的数据缓冲区,大小是offscreen的高度*宽度*每个像素点数据的大小。

闪烁是图形编程的一个常见问题。

需要多重复杂绘制操作的图形操作会导致呈现的图像闪烁或具有其他不可接受的外观。

双缓冲的使用解决这些问题。

双缓冲使用内存缓冲区来解决由多重绘制操作造成的闪烁问题。

当启用双缓冲时,所有绘制操作首先呈现到内存缓冲区,而不是屏幕上的绘图图面。

所有绘制操作完成后,内存缓冲区直接复制到与其关联的绘图图面。

因为在屏幕上只执行一个图形操作,所以消除了由复杂绘制操作造成的图像闪烁。

如何实现双缓冲
首先给出实现的程序,然后再解释,同样是在OnDraw(CDC *pDC)中:
CDC MemDC; //首先定义一个显示设备对象
CBitmap MemBitmap;//定义一个位图对象
//随后建立与屏幕显示兼容的内存显示设备
MemDC.CreateCompatibleDC(NULL);
//这时还不能绘图,因为没有地方画^_^
//下面建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小,也可以自己定义(如:有滚动条时就要大于当前窗口的大小,在BitBlt时决定拷贝内存的哪部分到屏幕上)
MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);
//将位图选入到内存显示设备中
//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上
CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);
//先用背景色将位图清除干净,这里我用的是白色作为背景
//你也可以用自己应该用的颜色
MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));
//绘图
MemDC.MoveTo(……);
MemDC.LineTo(……);
//将内存中的图拷贝到屏幕上进行显示
pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY);
//绘图完成后的清理
MemBitmap.DeleteObject();
MemDC.DeleteDC();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////
GDI+实现双缓冲的具体步骤
我再来详细解释一下刚才实现双缓冲的具体步骤:
1、在内存中建立一块“虚拟画布”:
Bitmap bmp = new Bitmap(600, 600);
2、获取这块内存画布的Graphics引用:
Graphics g = Graphics.FromImage(bmp);
3、在这块内存画布上绘图:
g.FillEllipse(brush, i * 10, j * 10, 10, 10);
4、将内存画布画到窗口中
this.CreateGraphics().DrawImage(bmp, 0, 0);。

相关文档
最新文档