|
楼主 |
发表于 2009-5-20 10:09:53
|
显示全部楼层
C++中如何实现窗口重绘并避免闪烁现象
C++中如何实现窗口重绘并避免闪烁现象
学习了才知道编程远非想像的那么简单,比如我们平时在电脑里看到的窗口被遮住或最小化之后,窗口里的内容是不会丢失的,这是一件最普通平常的事情了,但就是么这一件看似很简单自然的窗口重绘事情,实现起来却是很麻烦的,非可视化的编程软件似乎没有提供这种现成的设置,只能由程序员自己来实现。比如你在窗口里写上字,画上图,然后当你的窗口被其他窗口覆盖后,你窗口里的内容就会被抹掉,系统是不会帮你重画的,这时为了保证窗口里内容的完整性,你必须对窗口里的内容进行重画,而这个重画的工作只能由程序员自己来做。
最简单的做法是在程序收到系统发送过来的WM_PAINT窗口重绘消息时,把窗口里原来的内容再画一遍,这对于简单的文字和图画是比较简便可行的办法,但假如你显示的是一张地图,甚至是动态的图片,那就很麻烦了。而且重画期间,窗口还会出现闪烁现象,重画的频率越高,闪烁就越厉害,如果用这种方法来写游戏,无疑是很难行得通的。为此,我请教了很多高手,在很多QQ群里问了很多前辈,也在很多编程论坛上发过很多求教的贴子,都没有得到满意的答案。于是我决定自己来实现这一功能,终于经过两天的研究,我自己实现了不论在什么情况下,都能使窗口的内容保持原样,即使窗口被频繁的改变大小、移动或遮盖,也能使窗口里的内容保持原样并不会出现闪烁现象的功能。
我的设计思路是这样的:①在填充窗口类的时候,把窗口的背景刷设为空(可以避免出现闪烁现象,但不会自动擦除窗口内容);②在内存中开辟一块虚拟的后台显示区,把要显示在窗口中的内容先写到这个后台中;③用BitBlt()函数把内存后台显示区中的内容整块传送给窗口显示出来,然后在每次收到系统发送过来的WM_PAINT窗口重绘消息时,都使用一次BitBlt()函数把内存后台显示区中的内容整块传送给窗口,这样的效果就非常好了。
思路看起来并不复杂,但实现起来也不轻松,下面是源代码及注释:
HDC hdcmem; //定义后台内存显示设备句柄,这个要在主函数WinMain()外定义成全局变量,用以始终保持窗口内容。
//下面是显示完窗口以后的程序
HDC hdc; //定义窗口设备句柄变量
HBITMAP hBitmap; //定义一个位图句柄变量
hdc=GetDC(hwnd); //获得窗口客户区显示设备句柄
hdcmem=CreateCompatibleDC(hdc); //建立一个与实际设备兼容的内存设备
hBitmap = CreateCompatibleBitmap(hdc,600,800);
//创建与指定的设备环境相关的兼容位图,第一个参数是设备环境句柄;
//第二个参数是位图的宽度,第三个参数是位置的高度。
SelectObject(hdcmem,hBitmap); //该函数选择一对象到指定的设备环境中,第
//一个参数是指定设备的句柄,第二个参数是
//被选对象的句柄。只有先对内存显示设备句
//柄选入位图对象,才能对其进行画图操作。
TextOut(hdcmem,100,100,"很好!",strlen("很好!")); //往后台进行写操作或画图,想显示什么内容自己决定。
BitBlt(hdc,0,0,600,800,hdcmem,0,0,SRCCOPY); //把后台的内容整块复制显示到窗口中
ReleaseDC(hwnd,hdc); //释放显示器句柄
//下面是收到系统发送过来的WM_PAINT窗口重绘消息时的处理程序。
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps); //BeginPaint()和下面的EndPaint()是处理WM_PAINT消息的典型做法,这里不详细介绍。
//PS和HDC必须在回调函数里的前面重新定义,其中PS要定义成PAINTSTRUCT类型。
BitBlt(hdc,0,0,600,800,hdcmem,0,0,SRCCOPY); //重新把内存中的内容显示到窗口
EndPaint(hwnd,&ps);
break;
上面程序还不太完善,但已经能实现想要的功能了。这里不是编程交流区,可能大家对编程不是很熟悉,我就当学习日记一样的写出来,希望编程高手指导,太希望有一个好的老师了。
[ 本帖最后由 czy7812 于 2009-5-20 10:28 编辑 ] |
|