欢迎来到得力文库 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
得力文库 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    窗口闪烁 解决方案.docx

    • 资源ID:69491641       资源大小:113.90KB        全文页数:8页
    • 资源格式: DOCX        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    窗口闪烁 解决方案.docx

    Win32解决窗口闪耀(2022-09-06 10:41:40)转载标签:杂谈.htmlO、前提本文采纳Win32 SDK以及C/C+语言描述,其中没有用到C+语言的功能。采纳标准 Win32应用程序模型,即从WinMain()进入,然后使用RegisterClassEx。注册主窗口类, 同时主窗口的消息处理回调过程是WndProcQ,其它的一些变量和函数在文章中描述。一、闪耀的分类与缘由通常的闪耀分为:1 .窗口内容的闪耀,例如使用TextOut()直接在窗口客户端绘制文字等;2 .窗口子控件闪耀,例如窗口中的Button. TabControl闪耀等。全部闪耀的根本缘由只有一个,就是同一个像素使用不同的颜色值多次绘制,造成视觉上 的闪耀现象。而应用在上面两种闪耀的状况中,造成Windows为同一个像素绘制多次的成 因就分为很多种了:1 .窗口首先在WM_ERASEBKGND消息中使用背景画刷(假如在类样式中指定的话)擦除背景, 然后再在WM_PAINT中绘制内容(如之前说到的TextOut),造成了在内容处的同一个像素 绘制两次,从而造成了 TextOut输出的内容会不断闪耀;(这个现象在窗口每次需要 WM_PAINT时就会消失);2 .窗口在WM_PAINT绘制完内容之后向全部的子窗口发送WM_PAINT消息,从而造成全部 子窗口位置的像素首先被窗口的WM_PAINT绘制一次,其次被这个子窗口的内容绘制一次 (或多次),造成闪耀现象;3 .子窗口本身也需要处理W_ERASEBKGND和WM_PAINT消息,Windows有些系统控件本身 没有经过良好的优化,造成闪耀,例如TabControlo下面就消退这几种闪耀状况进行说明。二、合适的类样式和窗体样式最简洁的消退闪耀的方法就是首先需要指定合适的类样式(CS_*)和窗体样式(WS_*以及 WS_EX_*),选用相应的样式时可以考虑一下几点:1 .全部具有子窗口的父窗口都需要加入WS_CLIPCIIILDREN样式;2 .全部子窗口都需要加入WS_CLIPSIBLINGS样式;3 .谨慎考虑CSJIREDRAW和CS_VREDRAW,需要依据窗口客户区绘制的内容来打算;有关这些样式的具体解释参见MSDN或其它相关参考资料。其中只有第三个需要经过考虑, 此外两个几乎在全部的状况下都是需要遵循的。假如窗体绘制的内容之固定位置的,例如不 管窗口大小是什么只是在(15, 15)位置处输出固定的字符串,那就不需要加入这两个类样 式;但是假如窗口绘制的内容是需要依据窗口的大小不同而不同的,例如需要居中绘制一个 字符串,那么就必需加入这两个样式。三、双级冲技术双缓冲简而言之就是将绘制同一个像素的操作都在内存中静静进行,最终将整个内存图像一 次性复制到屏幕上,这样从屏幕的角度来看就是全部的像素都只绘制了一次。更多有关双缓 冲的介绍参考相关网站资料等,这里不再详述。双缓冲用于解决同一个窗口中的绘制问题,如WM_ERASEBKGND和WM_PAINT的处理、 Windows系统控件本身WM_PAINT的不足。具体来说就是使用TextOut()输出居中的字符 串 和Windows的TabControl控件本身的闪耀问题。首先处理TextOut ()的闪耀,以下列出相关的代码片断(在主窗口的WndProc消息处理中 的代码片断):case WM_ERASEBKGND:return TRUE; /不进行擦除背景,在WM_PAINT消息中进行擦除case WM_PAINT: /为了在case子句中声明局部变量,加入大括号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_HBRBACKGROUND) - 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) ; /复制内存图像到屏幕DeleteObject(memBM);DeleteDC(deBuffer);EndPaint(hWnd, &ps);break;窗口内容的绘制双缓冲就是这样的代码框架,然后是Windows系统控件TabControl,可能 是Windows在实现上的疏忽,即使父窗口用了 WS CLIPCHILDREN的状况下,在WindowsXP> Windows Vista/7的经典主题样式下,TabControl依旧会闪耀,经过一些简洁的分析 发觉是由于TabControl本身的WM ERASEBKGND不像其它标准控件那样可以避开闪耀,同 时还由于子窗口的WM_PAINT消息处理中也多次绘制了同一个像素造成了严峻的闪耀。因此需要对这一个控件进行“特别照看”;在写出代码片断之前,首先需要了解“控件子类 化”的概念,具体内容参见MSDN或其它相关文档,经典的方法是使用SetWindowLongPtrO 结合GWLPJVNDPROC进行子类化,但在Windows XP以后可以用更为简洁的SetWindowSubclassO 子类化一个控件。还需要了解的就是 “WM_PRINT、WM_PRINTCLIENT” 消息,它们都允许控件/窗口将当前的状态绘制到一个指定的HDC中,而不是WM.PAINT中 绘制到窗口 DC中,而且WM_PRINT内部在某些状况下会调用WM_PRINTCLIENT进行绘制, 因此我们的程序中只需要使用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;RECT 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 = 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消息的说明 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);EndPaint(hWnd, &ps);return TRUE;return DefSubclassProc(hWnd, uMsg, wParam, IParam); )/ 需要导入头文件 #include <commctrl. h>/ #pragma comment(libA nComCtl32.libn)/并且需要在WinMain开头时使用工N工TCOMMONCONTROLSEX icc;/ icc.dwSize = sizeof(INITCOMMONCONTROLSEX);/ icc.dwICC = ICC_TAB_CLASSES;/ InitCommonControlsEx(&icc);/这些代码来导入 Common Controls v6.0的DLL case WM_CREATE:hTab = CreateWindowEx (0, WC_TABCONTROL, TEXT (11U) f WS_CHILD | WS_VISIBLE | WS_CLIPCHILDRENZ 450, 100, 200, 500, hWndz NULL, GetModuleHandle(NULL), NULL); tabitem.mask = TCIF_TEXT | TCIF_IMAGE;tabitem.ilmage = -1;tabltem.pszText = TEXT ("Tab Item ln);TabCtrl_InsertItem(hTab, 0, Stabltem);tabltem.pszText = TEXT("Tab Item 2");TabCtrl_InsertItem(hTab, 1r Stabltem);SetWindowSubclass(hTab, TabCtrlProc, 0, 0);break;WM_PRINT消息绘制的内容和WM_PAINT绘制到窗口 DC上的内容是几乎完全全都的,包括 鼠标交互、键盘交互、焦点框、颜色变化等,但是之所以说“几乎"是由于在处理Windows Vista/7的Aero主题下的一些动画过程不会在WM PRINT过程中体现,但是由于 TabControl在Aero主题下也根本没有动画效果,因此不会影响。四、消退子窗口闪耀这个方法一般被称为是一种“错觉”,即消退闪耀只是看上去的一种错觉而已,为何称为“错 觉”在描述完之后再进行分析。该方法主要用于一些透亮的窗体,最闻名的就是例如BS_GROUPBOX样式的Button,在全部的标准控件中,可以说GroupBox的闪耀问题是 最为臭名昭著的,也是最难以解决的,由于假如像其它控件的父窗口一样在它的父窗口中加 入WS_CLIPCIIILDREN样式,那么它的背景就相当于完全没有绘制,由于事实上BS_GROUPBOX 是透亮的,具体结果可以自行编码试验。而假如将WS_EX_TRANSPARENT样式加入到GroupBox中,由于每次窗体都会绘制背景,所 以这又会造成严峻的闪耀问题。这里说到的一种解决方案就是在绘制父窗口的背景的时候将 这个控件的内容也作为背景进行绘制,这样就算绘制两次,也是绘制两次同样颜色的像素, 而造成闪耀的缘由是由于绘制多次不同颜色的像素(参见第一节),即比如说父窗口 hWnd有 一个子控件hGroup,它是一个BS GR0UPB0X,然后在hWnd的客户区域除了绘制TextOut () 的字符串以外,在hGroup相应位置的背景也需要使用第三节提到的WM_PRINT消息来绘 制,即擦除窗口背景的时候就同时绘制了这个控件,而窗口背景有用双缓冲技术避开闪耀的, 当然最终控件本身再在这个背景的基础上绘制自身,相当于用同样的像素再次掩盖这个背 景;因此即使还是绘制了两次,但是由于用的是相同颜色的像素(由于MSDN中有提到 Windows标准控件的WM_PAINT和WM_PRINT消息绘制的内容是一样的),因此也就给用户 感觉没有闪耀。相关的代码片断如下(主窗口的WndProc消息处理中,代码中省略了之前两节的代码,最 终可以将它们都合并起来,同时也省略了变量的声明,其中hGroup是全局变量,其它都是 局部变量,rGroup是RECT类型):case WM_CREATE:hGroup = CreateWindowEx(WS_EX_TRANSPARENT, WC_BUTTON, TEXT(nGroupBoxn), WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_CLIPSIBLINGS, 100z 100, 300, 500z hWnd, NULL, GetModuleHandle(NULL), NULL);break;case WM_CTLCOLORSTATIC:return NULL; /将GroupBox的标题背景也设置为透亮 ,否则将会有一些惊奇的颜色消失case WM_PAINT:GetClientRect (hWnd, Srect) ; / 猎取窗口客户区矩形GetWindowRect (hGroup, &rGroup) ; / 猎取 GroupBox 矩形(屏幕坐标)ScreenToClient (hWnd, (LPPOINT) (SrGroup . lef t) ) ; / 将 GroupBox 矩形从屏幕坐标转换 成客户区坐标hdc = BeginPaint(hWnd, &ps);deBuffer = CreateCompatibleDC(hdc);memBM = CreateCompatibleBitmap(hdcz rect.right - rect.left, rect.bottom - rect top);SelectObject (deBuffer, memBM) ; / 双缓冲资源建立完毕FillRect(deBuffer, &rect, (HBRUSH) (GetClassLong(hWnd, GCL_HBRBACKGROUND) - 1); /绘制窗口背景色SetWindowOrgEx (deBuffer, -rGroup . left, -rGroup. top, NULL) ; / 将坐标系原点平移至 U GroupBox左上角SendMessage(hGroup, WM_PR工NT, (WPARAM)(deBuffer)z PRF_CLIENT | PRF_NONCLIENT); /调用系统默认的GroupBox绘制函数SetWindowOrgEx (deBuffer, 0, 0, NULL) ; / 将坐标系,恢复至!J原来的位置BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, dcBuffer, 0, 0, SRCCOPY);DeleteObject (memB;/清理双缓冲资源DeleteDC(deBuffer);EndPaint(hWnd, &ps); return TRUE;在代码中消失的相关API都可以参考MSDN或相关文档。和第三节提到的关于Aero主题 下的动画问题一样,这个方法假如应用于一些具有不断动画的控件(如具有键盘焦点的按钮) 上时会不尽如人意,但好在BS_GROUPBOX没有动画,而且全部有关透亮的控件都没有动画。同样这个方法不仅仅适用于窗口上,也适用于子控件上,例如TabControlo五、更多解决方案除了上面提到的几种方法以外,还有很多其它的解决方案,有些更为彻底,而有些有稍许的 BUGo首先当然就是Windows XP引入的WS_EX_COMPOSITED 样式,这个样式在Windows内部为 你进行整个窗口(包括客户绘制和全部的子孙窗口)的双缓冲,然后一次性显示到屏幕上, 在Windows XP、Vista/7以及它们的经典主题中都可以正确使用,而且闪耀效果能够得到 完善的消退,性能也不错。但只有一个缺点,那就是在Windows XP主题,或Win Vista/7 的Aero Basic主题下,标题栏的按钮不会有高亮效果,这个算是它的一个BUG。而在 Windows Vista/7的一般Aero主题(即开启透亮效果)中,由于非客户区是交给DWM进行绘制的,因此不会影响,可以说在开启透亮效果Aero主题下这个样式可以做到完善解决,而且特别的简便,只需要将父窗口的扩展样式添加 WS_EX_COMPOSITED即可(至今没有见到过有商业程序使用这个样式来避开闪耀)。其次种方法也是采用Windows XP引入的WS_EX_LAYERED样式,这个样式是用于设置窗口 透亮度或透亮颜色掩码的,但是假如应用了这个样式,并且透亮度设置到254 (255表示完全不透亮),这样用户察觉不到有那么大约0.5%不到的透亮度,同时在内部Windows也会将其作为双缓冲处理,并且在全部主题下,非客户区的按钮(最小化、最大化、关闭按钮等)都能正确地进行交互,而不像 WS_EX_COMPOSITED样式在某些主题下非客户区按钮在鼠标移动上去时没有高亮效果。这个 方法的缺点就是性能很低,绘制效果特别慢(没有见过有使用这个样式来避开闪耀而不是 处理透亮的商业程序实例)。第三种方法就是使用其它的库,例如WPF,它内部使用了无HWND的技术,整个窗体的子控 件都没有HWND,这样整个窗体的绘制工作就能由主窗体全权掌管,自然也就完全不闪耀了 (例如 Visual Studio 2022)。第四种方法,就是要么忽视不计,允许窗口有烦人的闪耀问题,并期盼今后的操作系统有更 完善的解决方案,而事实上Windows Vista/7在避开闪耀的问题上的确做了不少很有成效 的努力,但仍不够完善(例如Visual Studio 2022的查找对话框);要么就将窗口设置 为不能调整大小,也能完全避开闪耀(例如Office Word等很多Windows附带程序的对 话框)。六、应用采用第一节到第四节的一些功能,在Windows环境下的绝大多数闪耀问题都可以完善解决, 但是也并不是全部的环境中都需要使用这个技术。例如在一些无法调整大小的对话框中,根 本就无需考虑闪耀问题,由于根本就不会发生由于调整大小而产生的闪耀。对于BS_GROUPBOX,需要使用第四节的方法,对于TabControl和窗口背景的绘制需要使用 第三节的方法,对于全部其它的标准空间只需要在父窗口中包含WS_CLIPCHILDREN样式即 可解决。下图就是使用以上方法绘制的一些控件和窗口背景,可以看到在处理TabControl时的一些 问题,如Button按钮的背景四周有一圈蓝色,这是由于它的父窗口设置成为了主窗口的原 因,而假如把按钮的父窗口设置成为TabControl,则背景就正常了,成为Button2oGroupBox 的父窗口也设置成为了 TabControl,这个程序在XP的Luna主题下、Win Vista/7的 Aero主题下,或任何Windows经典主题下到表现良好(右下角的调整框也是绘制在窗口背 景中的,调用了相关的Theme API,并且处理了 WM_NCHITTEST消息,参考MSDN)。¥in32Ent ryTest七、后续工作这里只解决了自己注册窗口类的一些窗口问题,而没有处理到对话框,但原理都是一样的。 这里处理TabControl的方法是自己建立控件并进行子类化,并且把TabControl作为父窗 口来承载它的子窗口,但在Windows中更为通用的方法是使用一些对话框单独编辑每一页的 控件集合,并且和TabControl之间并不是父子关系,而是兄弟关系(Siblings),这一点 在以后的文章中会争论到。共享:

    注意事项

    本文(窗口闪烁 解决方案.docx)为本站会员(太**)主动上传,得力文库 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知得力文库 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于得利文库 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

    © 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

    黑龙江省互联网违法和不良信息举报
    举报电话:0468-3380021 邮箱:hgswwxb@163.com  

    收起
    展开