相信很多人在做图形界面开发时,常常会遇到屏幕闪烁的情况,当然我也不例外。前段时间用vc++做了一个小游戏——五子棋,前期阶段主要做的是逻辑层面的编码,没有太注意屏幕闪烁的情况,到了后来实现悔棋功能时需要擦除已下过的棋子进行重绘,屏幕闪烁厉害,急需解决——有哪个玩家愿意玩屏幕老闪烁的游戏? 通常来说程序根据需要调用Invalidate(FALSE)使窗口客户区无效引起重绘,然后在窗口OnPaint函数(基于文档视图的程序则是OnDraw)中进行稳定绘图就行了。但是,我们在OnPaint中进行多重绘制(画背景、棋盘、棋子等),前后绘制的反差造成了闪烁现象。以前知道Java中解决屏幕闪烁问题是用双缓冲的方法,现在发现在vc++中也是可以这么做的。简单来说,双缓冲就是先把需要绘制的东西全部一口气画在内存中,最后把内存中的数据搬到屏幕上显示。五二电子网 管理员组文章数量: 1493
下面是双缓冲的代码实现例子:
点击(此处)折叠或打开
void C****Dlg::OnPaint()
{
if (IsIconic())
{
//......
}
else
{
//CDialog::OnPaint(); //不要调用这个
CPaintDC dc(this);//对话框的dc//通常CPaintDC用来响应WM_PAINT消息。
//CPaintDC是从CDC派生出来的:在构造时自动调用CWnd::BeginPaint,析构时调用CWnd::EndPaint。
RECT rect;// 客户区矩形
GetClientRect(&rect);
// 使用双缓冲避免屏幕刷新时闪烁
CDC dcMem;// 内存dc
CBitmap bmpMem; // 位图
dcMem.CreateCompatibleDC(NULL);// 创建兼容dc
bmpMem.CreateCompatibleBitmap(&dc, rect.right-rect.left, p);//创建跟客户区域大小一样的(空)位图
// 把位图选到设备上下文环境中
CBitmap *pOld = dcMem.SelectObject(&bmpMem);
// dcMem.FillSolidRect(&rect, RGB(255,255,255));
// 在此处将绘制内容全画到dcMem内存中,(即把之前使用CPaintDC绘制的dc换成dcMem即可)
DrawTable(dcMem);//画棋盘
DrawChesses(dcMem); // 画棋子
//......
// 至此,内存中绘图完毕
// 从内存拷贝到设备dc
dc.BitBlt(0, 0, rect.right - rect.left, rect.bottom - p, &dcMem, 0, 0, SRCCOPY);
dc.SelectObject(pOld);
// 释放资源
bmpMem.DeleteObject();
dcMem.DeleteDC();
}
}
PS:屏幕闪烁问题虽然得到解决了,但是窗口上的按钮却还会闪(可能是因为使用图片按钮的缘故才那么明显),当然这个我也是无法容忍的。
默认情况窗口风格没有设置了WS_CLIPCHILDREN属性,所以父窗口刷新时子窗口也跟着刷新,于是产生按钮闪烁现象,于是我在游戏开始时给窗口加上WS_CLIPCHILDREN属性:
ModifyStyle(0, WS_CLIPCHILDREN);
这样Invalidate 时按钮就不会闪烁了。
如果窗口加上了WS_CLIPCHILDREN属性,当需要切换背景图片时,按钮因为没有刷新所以会被盖住,直到(鼠标移到按钮上)重绘时才会显示出来。
解决方法:
1)添加BOOL类型的成员变量bgroundChanged,初始化为FALSE;
2)在切换背景图片前调用ModifyStyle(WS_CLIPCHILDREN, 0)去掉WS_CLIPCHILDREN属性,并把bgroundChanged设置为TRUE;
3)在OnPaint中最后增加
if (TRUE == bgroundChanged)
{
bgroundChg = FALSE;
ModifyStyle(0, WS_CLIPCHILDREN);
}
版权声明:本文标题:如何解决vc++绘图出现屏幕闪烁的问题 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1686494130h1969.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论