不用双缓冲图像也能解决画面闪烁!!!

最近一直在看CSDN雾央大神的vc++游戏教程,但由于他用的是vs2010,有些类在vc6.0中并没有,所以学起来有吃力,不过还好,今天发现了一个大问题和一些小问题。。。。
1、       在vs2010中"不使用文档/查看体系结构支持"(标记为1)的MFC中可以很方便的添加消息响应函数和OnPaint()函数,但是vc6.0在类向导中就很难找到这些函数了,出于方便,我就选择了“文档/查看体系结构支持”(标记为2)的MFC结构,但是问题又来了,这个出来默认只有OnDraw函数而没有OnPaint函数,所以一开始我就索性把绘制画面和接受消息的功能都设置在了OnDraw中,但是当使用双缓冲时,还是没能解决画面闪烁的问题。这个时候我干脆新增一个OnPaint ()来处理画面绘制和消息接受,出乎我意料,画面闪烁的问题居然解决了!!!尼玛,有点坑,有点凌乱了,不过能找到这样一个方法,还是挺爽的。。。。

void CTest26View::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
a = point.x;
b = point.y;
Invalidate();                                    //在这里用Invalidate使窗口客户区无效之后,还要在OnPaint中通过ValidateRect使重绘的画面有效,这样就能神奇般的解决画面闪烁问题了
}

void CTest26View::OnPaint() 
{
//CPaintDC dc(this); // device context for painting
CRect rect;
GetClientRect(rect);
    CDC *pDC = this->GetDC();
CDC dc;
dc.CreateCompatibleDC(pDC);
CBitmap bitmap1,bitmap2,bitmap3;
bitmap1.LoadBitmap(IDB_BITMAP1);
bitmap2.LoadBitmap(IDB_BITMAP2);
bitmap3.LoadBitmap(IDB_BITMAP3);
dc.SelectObject(bitmap1);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);
dc.SelectObject(bitmap3);
pDC->BitBlt(a,b,a+128,b+128,&dc,0,0,SRCAND);
dc.SelectObject(bitmap2);
pDC->BitBlt(a,b,a+128,b+128,&dc,0,0,SRCPAINT);
    ValidateRect(rect);                        //如果前面没有Invalidate而只在这里使用Validate的话,画面依然闪烁,呵呵。。。
ReleaseDC(pDC);  
// TODO: Add your message handler code here
// Do not call CView::OnPaint() for painting messages
}
上面所说的解决画面闪烁只是背景不闪了,但是人物依然在闪,难道还要使用双缓冲吗,确实,当使用了双缓冲技术之后,背景图和人物都不闪了。。。。。。。
void CTest26View::OnPaint() 
{
//CPaintDC dc(this); // device context for painting
CRect rect;
GetClientRect(rect);
    CDC *pDC = this->GetDC();
    CDC bufferDC;
CBitmap bmpDC;
bufferDC.CreateCompatibleDC(pDC);
bmpDC.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
bufferDC.SelectObject(bmpDC);


CDC dc;
dc.CreateCompatibleDC(pDC);
CBitmap bitmap1,bitmap2,bitmap3;
bitmap1.LoadBitmap(IDB_BITMAP1);
bitmap2.LoadBitmap(IDB_BITMAP2);
bitmap3.LoadBitmap(IDB_BITMAP3);
dc.SelectObject(bitmap1);
bufferDC.BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY);
dc.SelectObject(bitmap3);
bufferDC.BitBlt(a,b,a+128,b+128,&dc,0,0,SRCAND);
dc.SelectObject(bitmap2);
bufferDC.BitBlt(a,b,a+128,b+128,&dc,0,0,SRCPAINT);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&bufferDC,0,0,SRCCOPY);
    ValidateRect(rect); 
ReleaseDC(pDC);  
// TODO: Add your message handler code here
// Do not call CView::OnPaint() for painting messages
}

在这个过程中,又发现了一个小问题,就是使用定时器的时候,没有使用Validate而只是使用Invalidate,开启定时器的时候人物并没有移动,而键盘和鼠标效应却可以,这是什么原因??

最后,插个小知识,转载。。
Invalidate():
     该函数的作用是使整个窗口客户区无效。窗口的客户区无效意味着需要重绘,例如,如果一个被其它窗口遮住的窗口变成了前台窗口,那么原来被遮住的部分就是无效的,需要重绘。这时Windows会在应用程序的消息队列中放置WM_PAINT消息。MFC为窗口类提供了WM_PAINT的消息处理函数OnPaint,OnPaint负责重绘窗口。视图类有一些例外,在视图类的OnPaint函数中调用了OnDraw函数,实际的重绘工作由OnDraw来完成。参数bErase为TRUE时,重绘区域内的背景将被擦除,否则,背景将保持不变。
   Invalidate标记一个需要重绘的无效区域,并不意味着调用该函数后就立刻进行重绘。 Invalidate只是放一个WM_PAINT消息在队列里,不做别的,所以只有当当前函数返回后,进入消息循环,取出WM_PAINT,才执行PAINT,所以不管Invalidate放函数哪个地方,(作用相当于)都是(放在)最后的(但并不是推荐你一律放在函数最后一行)。
----------------------------------------------------------------------------------------------------------------------------------------------
一般 Windows 会发送两个消息 WM_PAINT (通知客户区   有变化)和 WM_NCPAINT (通知非客户区有变化)。非客户区的重画系统自己搞定了,而客户区的重画需要我们自己来完成。这就需要 OnDraw()  OnPaint() 来重画窗口。

OnDraw()
OnPaint() 有什么区别呢?首先:我们先要明确 CView 类派生自 CWnd 类。而 OnPaint() CWnd 的类成员,同时负责响应 WM_PAINT 消息。 OnDraw() CVIEW 的成员函数,并且没有响应消息的功能。这就是为什么你用 VC 成的程序代码时,在视图类只有  OnDraw 没有 OnPaint 的原因。
当视图变得无效时(包括大小的改变,移动,被遮盖等等), Windows   WM_PAINT  消息发送给它。该视图的  OnPaint  处理函数通过创建  CPaintDC  类的 DC 对象来响应该消息并调用视图的  OnDraw  成员函数。通常我们不必编写重写的  OnPaint  处理成员函数。
2、另外一个小问题,就是当在头文件中声明缓冲内存和缓冲位图,最后一定要使用DeleteDC()和DeleteObject()释放,不然运行的时候会出现死机情况。但是直接在OnPaint()中直接定义的时候即使不释放内存也不会产生这种情况。。。。所以,一定要养成即使释放的习惯

转载于:https://www.cnblogs.com/tanjianwen/p/5245405.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值