Chinaunix首页 | 论坛 | 博客
  • 博客访问: 509672
  • 博文数量: 23
  • 博客积分: 398
  • 博客等级: 一等列兵
  • 技术积分: 850
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-03 22:18
文章分类

全部博文(23)

文章存档

2013年(9)

2012年(14)

分类: Windows平台

2013-10-01 22:32:15

      相信很多人在做图形界面开发时,常常会遇到屏幕闪烁的情况,当然我也不例外。前段时间用vc++做了一个小游戏——五子棋,前期阶段主要做的是逻辑层面的编码,没有太注意屏幕闪烁的情况,到了后来实现悔棋功能时需要擦除已下过的棋子进行重绘,屏幕闪烁厉害,急需解决——有哪个玩家愿意玩屏幕老闪烁的游戏? 通常来说程序根据需要调用Invalidate(FALSE)使窗口客户区无效引起重绘,然后在窗口OnPaint函数(基于文档视图的程序则是OnDraw)中进行稳定绘图就行了。但是,我们在OnPaint中进行多重绘制(画背景、棋盘、棋子等),前后绘制的反差造成了闪烁现象。以前知道Java中解决屏幕闪烁问题是用双缓冲的方法,现在发现在vc++中也是可以这么做的。简单来说,双缓冲就是先把需要绘制的东西全部一口气画在内存中,最后把内存中的数据搬到屏幕上显示。

下面是双缓冲的代码实现例子:

点击(此处)折叠或打开

  1. void C****Dlg::OnPaint()
  2. {
  3.     if (IsIconic())
  4.     {
  5.         //......
  6.     }
  7.     else
  8.     {
  9.         //CDialog::OnPaint(); //不要调用这个
  10.         CPaintDC dc(this);//对话框的dc//通常CPaintDC用来响应WM_PAINT消息。
  11.         //CPaintDC是从CDC派生出来的:在构造时自动调用CWnd::BeginPaint,析构时调用CWnd::EndPaint。
  12.         
  13.         RECT rect;// 客户区矩形
  14.         GetClientRect(&rect);
  15.         
  16.         // 使用双缓冲避免屏幕刷新时闪烁
  17.         CDC dcMem;// 内存dc
  18.         CBitmap bmpMem; // 位图
  19.         dcMem.CreateCompatibleDC(NULL);// 创建兼容dc
  20.         bmpMem.CreateCompatibleBitmap(&dc, rect.right-rect.left, rect.bottom-rect.top);//创建跟客户区域大小一样的()位图
  21.         // 把位图选到设备上下文环境中
  22.         CBitmap *pOld = dcMem.SelectObject(&bmpMem);
  23.         //    dcMem.FillSolidRect(&rect, RGB(255,255,255));    
  24.         // 在此处将绘制内容全画到dcMem内存中,(即把之前使用CPaintDC绘制的dc换成dcMem即可)
  25.     
  26.         DrawTable(dcMem);//画棋盘
  27.         DrawChesses(dcMem); // 画棋子
  28.         //......
  29.         // 至此,内存中绘图完毕
  30.         
  31.         // 从内存拷贝到设备dc
  32.         dc.BitBlt(0, 0, rect.right - rect.left, rect.bottom - rect.top, &dcMem, 0, 0, SRCCOPY);
  33.         
  34.         dc.SelectObject(pOld);
  35.         // 释放资源
  36.         bmpMem.DeleteObject();
  37.         dcMem.DeleteDC();
  38.         
  39.     }    
  40.     
  41. }

PS:屏幕闪烁问题虽然得到解决了,但是窗口上的按钮却还会闪(可能是因为使用图片按钮的缘故才那么明显),当然这个我也是无法容忍的。
默认情况没有设置了WS_CLIPCHILDREN属性,所以父窗口刷新时子窗口也跟着刷新,于是产生按钮闪烁现象,于是我在游戏开始时给窗口加上WS_CLIPCHILDREN属性:
(0, WS_CLIPCHILDREN);
这样Invalidate 时按钮就不会闪烁了。
如果窗口加上了WS_CLIPCHILDREN属性,当需要切换背景图片时,按钮因为没有刷新所以会被盖住,直到(鼠标移到按钮上)重绘时才会显示出来。
解决方法:
1)添加BOOL类型的成员变量bgroundChanged,初始化为FALSE;
2)在切换背景图片前调用(WS_CLIPCHILDREN, 0)去掉WS_CLIPCHILDREN属性,并把bgroundChanged设置为TRUE;
3)在OnPaint中最后增加
        if (TRUE == bgroundChanged)
        {
            bgroundChg = FALSE;
            ModifyStyle(0, WS_CLIPCHILDREN);
        }

注:本博客的文章除注明有“转载”字样的外,均为原创,欢迎转载,请注明文字出处 http://blog.chinaunix.net/uid-27034868-id-3930038.html
阅读(9187) | 评论(0) | 转发(0) |
0

上一篇:显示数字的LED字符

下一篇:没有了

给主人留下些什么吧!~~