窗口闪烁 解决方案.docx
《窗口闪烁 解决方案.docx》由会员分享,可在线阅读,更多相关《窗口闪烁 解决方案.docx(8页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、Win32解决窗口闪耀(2022-09-06 10:41:40)转载标签:杂谈.htmlO、前提本文采纳Win32 SDK以及C/C+语言描述,其中没有用到C+语言的功能。采纳标准 Win32应用程序模型,即从WinMain()进入,然后使用RegisterClassEx。注册主窗口类, 同时主窗口的消息处理回调过程是WndProcQ,其它的一些变量和函数在文章中描述。一、闪耀的分类与缘由通常的闪耀分为:1 .窗口内容的闪耀,例如使用TextOut()直接在窗口客户端绘制文字等;2 .窗口子控件闪耀,例如窗口中的Button. TabControl闪耀等。全部闪耀的根本缘由只有一个,就是同一个
2、像素使用不同的颜色值多次绘制,造成视觉上 的闪耀现象。而应用在上面两种闪耀的状况中,造成Windows为同一个像素绘制多次的成 因就分为很多种了:1 .窗口首先在WM_ERASEBKGND消息中使用背景画刷(假如在类样式中指定的话)擦除背景, 然后再在WM_PAINT中绘制内容(如之前说到的TextOut),造成了在内容处的同一个像素 绘制两次,从而造成了 TextOut输出的内容会不断闪耀;(这个现象在窗口每次需要 WM_PAINT时就会消失);2 .窗口在WM_PAINT绘制完内容之后向全部的子窗口发送WM_PAINT消息,从而造成全部 子窗口位置的像素首先被窗口的WM_PAINT绘制一次
3、,其次被这个子窗口的内容绘制一次 (或多次),造成闪耀现象;3 .子窗口本身也需要处理W_ERASEBKGND和WM_PAINT消息,Windows有些系统控件本身 没有经过良好的优化,造成闪耀,例如TabControlo下面就消退这几种闪耀状况进行说明。二、合适的类样式和窗体样式最简洁的消退闪耀的方法就是首先需要指定合适的类样式(CS_*)和窗体样式(WS_*以及 WS_EX_*),选用相应的样式时可以考虑一下几点:1 .全部具有子窗口的父窗口都需要加入WS_CLIPCIIILDREN样式;2 .全部子窗口都需要加入WS_CLIPSIBLINGS样式;3 .谨慎考虑CSJIREDRAW和CS
4、_VREDRAW,需要依据窗口客户区绘制的内容来打算;有关这些样式的具体解释参见MSDN或其它相关参考资料。其中只有第三个需要经过考虑, 此外两个几乎在全部的状况下都是需要遵循的。假如窗体绘制的内容之固定位置的,例如不 管窗口大小是什么只是在(15, 15)位置处输出固定的字符串,那就不需要加入这两个类样 式;但是假如窗口绘制的内容是需要依据窗口的大小不同而不同的,例如需要居中绘制一个 字符串,那么就必需加入这两个样式。三、双级冲技术双缓冲简而言之就是将绘制同一个像素的操作都在内存中静静进行,最终将整个内存图像一 次性复制到屏幕上,这样从屏幕的角度来看就是全部的像素都只绘制了一次。更多有关双缓
5、 冲的介绍参考相关网站资料等,这里不再详述。双缓冲用于解决同一个窗口中的绘制问题,如WM_ERASEBKGND和WM_PAINT的处理、 Windows系统控件本身WM_PAINT的不足。具体来说就是使用TextOut()输出居中的字符 串 和Windows的TabControl控件本身的闪耀问题。首先处理TextOut ()的闪耀,以下列出相关的代码片断(在主窗口的WndProc消息处理中 的代码片断):case WM_ERASEBKGND:return TRUE; /不进行擦除背景,在WM_PAINT消息中进行擦除case WM_PAINT: /为了在case子句中声明局部变量,加入大括号
6、HDC hdc = BeginPaint(hWnd, &ps);RECT rect;GetClientRect(hWnd, Srect);HDC dcBuffer = CreateCompatibleDC(hdc);HBITMAP memBM = CreateCompatibleBitmap(hdc, rect.right - rect工eft, rect.bottom -rect. top) ; /创建内存图像Selectobject(deBuffer, memBM);FillRect(deBuffer, &rect, (HBRUSH)(GetClassLong(hWnd, GCL_HBRB
7、ACKGROUND) - 1); /擦除背景,WM_ERASEBKGND标准的处理方法,但是这需要在窗口类的声明中将wc . hbrBackground =(HBRUSH) (COLOR_BTNFACE + 1); 写入这样的代码DrawText(deBuffer, TEXT(nHelloz Windows!n)z -1, &rect, DT_CENTER | DT_VCENTER I DT_S工NGLEL工NE);BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, deBuffer, 0, 0, SRCCOPY)
8、 ; /复制内存图像到屏幕DeleteObject(memBM);DeleteDC(deBuffer);EndPaint(hWnd, &ps);break;窗口内容的绘制双缓冲就是这样的代码框架,然后是Windows系统控件TabControl,可能 是Windows在实现上的疏忽,即使父窗口用了 WS CLIPCHILDREN的状况下,在WindowsXP Windows Vista/7的经典主题样式下,TabControl依旧会闪耀,经过一些简洁的分析 发觉是由于TabControl本身的WM ERASEBKGND不像其它标准控件那样可以避开闪耀,同 时还由于子窗口的WM_PAINT消息处
9、理中也多次绘制了同一个像素造成了严峻的闪耀。因此需要对这一个控件进行“特别照看”;在写出代码片断之前,首先需要了解“控件子类 化”的概念,具体内容参见MSDN或其它相关文档,经典的方法是使用SetWindowLongPtrO 结合GWLPJVNDPROC进行子类化,但在Windows XP以后可以用更为简洁的SetWindowSubclassO 子类化一个控件。还需要了解的就是 “WM_PRINT、WM_PRINTCLIENT” 消息,它们都允许控件/窗口将当前的状态绘制到一个指定的HDC中,而不是WM.PAINT中 绘制到窗口 DC中,而且WM_PRINT内部在某些状况下会调用WM_PRIN
10、TCLIENT进行绘制, 因此我们的程序中只需要使用WM_PRINT消息即可,依据MSDN的描述,全部的Windows系 统控件都实现了这两个消息。以下是处理TabControl闪耀的代码:/ TabControl的子类化回调函数(具体内容参见MSDN的Subclass Controls 一章)LRESULT CALLBACK TabCtrlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM IParam, UINT_PTR, DWORD_PTR) (HDC hdc, deBuffer;HBITMAP memBM;PAINTSTRUCT ps;RE
11、CT rect;switch (uMsg) case WM_ERASEBKGND:/由于默认状况下本消息中IParam传入的是0,因此默认状况下不进行绘制,以避开闪耀;但假如 传入的是TRUE,那么表示是由以下在处理WM_PAINT消息的代码调用的,因此需要调用默认的绘制代 码,也就是break到switch语句之外if (!IParam)return TRUE;break;case WM_PAINT:GetClientRect(hWndz Srect);hdc = BeginPaint(hWndz &ps);dcBuffer = CreateCompatibleDC(hdc);memBM =
12、 CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect , top);SelectObject (deBuffer, memBM) ; /以上双缓冲代码和之前的是一样的SendMessage (hWnd, WM_ERASEBKGND, (WPARAM) (deBuffer) z TRUE) ; / 发送 WM_ERASEBKGND消息并传入IParam为TRUE, wParam为缓冲的DC,要求默认处理程序将背景擦 除过程应用到deBuffer上,具体内容参见MSDN中关于WM_ERASEBKGND消息的说
13、明 SendMessage(hWnd, WM_PRINT, (WPARAM)(deBuffer), PRF_CLIENT | PRF_NONCLIENT); / 发送WM_PRINT,要求控件将当前状态绘制到deBuffer,具体内容参见MSDN中关于WM_PRINT和 WM_PRINTCLIENT 消息的说明BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, deBuffer, 0,0, SRCCOPY) ; /复制到屏幕并清理内存图像DeleteObject(memBM);DeleteDC(deBuffer);
14、EndPaint(hWnd, &ps);return TRUE;return DefSubclassProc(hWnd, uMsg, wParam, IParam); )/ 需要导入头文件 #include / #pragma comment(libA nComCtl32.libn)/并且需要在WinMain开头时使用工N工TCOMMONCONTROLSEX icc;/ icc.dwSize = sizeof(INITCOMMONCONTROLSEX);/ icc.dwICC = ICC_TAB_CLASSES;/ InitCommonControlsEx(&icc);/这些代码来导入 Com
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 窗口闪烁 解决方案 窗口 闪烁
限制150内