CImageButtonWithStyle -按钮使用图像与XP视觉风格

介绍 想象一下,您终于开始在MFC应用程序中添加一个清单文件,这样您的所有控件都将利用新的XP视觉样式。你的一个对话框将按钮与普通的文本标题以及使用图像作为标题的按钮混合,它最终看起来是这样的: 那不是你想要的!带有文本标签的按钮按照你期望的方式出现,但是那些使用图像的按钮忽略了XP的视觉样式设置,而使用的是旧的3d效果。你想要你所有的按钮使用XP视觉风格,像这样: CImageButtonWithStyle是一个很简单的类,它不会改变应用程序在xp之前的Windows版本上的运行方式。 背景 在Windows XP下运行时,Windows应用程序不会自动使用通用控件库comctl32.dll的新“主题感知”版本。您的应用程序必须包含一个清单文件作为它的资源之一,以告诉Windows您希望使用该库的新版本,因为存在一些小的不兼容性。有关更多细节,请参阅Jian Hong的文章Add XP Theme Style to your current projects(或查看本文的演示应用程序)。 如果您只是想测试发生了什么,而不进行永久性的更改,那么只需将适当的清单文件复制到与可执行文件appname.exe相同的目录中,并将其重命名为appname.exe.manifest。 您将注意到,使用图标或位图(使用窗口样式标志BS_ICON或BS_BITMAP)的按钮以您在没有使用视觉样式时所期望的3d效果呈现。这种行为在某些情况下是有意义的,比如完全填充按钮表面的位图。在其他情况下,比如混合符号和文本标题时,它看起来很难看。 您可能会认为有一个简单的解决方案可以选择新的外观(比如扩展的样式标志),但是我没有找到。有许多出版解决方案使用BS_OWNERDRAW风格完全接管所有按钮呈现,但这意味着重新实现按钮控件的最基本的行为(见文章由委员会或原生Win32 Davide Calabro CXPStyleButtonST v1.2主题意识到自绘制控件没有MFC伊万·沃德)。很难确定这些类在其他方面会像普通的窗口按钮控件一样运行。 忘记BS_OWNERDRAW,只使用NM_CUSTOMDRAW代替 幸运的是,SfaeJ给Ewan Ward的文章加了一条评论,让我走上了正确的道路。在使用较新的comctl32版本运行时。按钮控件发送NM_CUSTOMDRAW通知。一旦我知道该寻找什么,我就能够在微软的文档中找到一些小细节,并得到一个可行的解决方案。 使用的代码 使用CImageButtonWithStyle很简单。 首先,将类CImageButtonWithStyle和它的助手类CVisualStylesXP的源文件添加到您的项目(四个文件:ImageButtonWithStyle)。h, ImageButtonWithStyle。cpp, visualstyles .h和visualstyles .cpp)。 为每个按钮在对话框中添加一个CButton成员,它将显示一个图像并将其与Windows控件关联。如果您使用Visual Studio类向导,它将添加成员变量并添加对DDX_Control的调用(在您的CDialog派生类的DoDataExchange() override中)。这将把CButton实例与对话框模板创建的Windows控件关联起来。隐藏,复制co全无CSampleDlg::DoDataExchange(CDataExchange* pDX) { CDialog: DoDataExchange (pDX); DDX_Control (pDX IDC_BUTTON m_wnd_button); //其他DDX_和DDV_调用 } 现在,添加行#include“ImageButtonWithStyle”。更改CButton成员的声明,改为使用CImageButtonWithSyle类。隐藏,复制CodeCImageButtonWithStyle m_wnd_button; 重新编译,就完成了。 如果你想使用CImageButtonWithStyle在其他情况下,你将不得不叫SubclassDlgItem()或SubclassWindow()来将CImageButtonWithStyle实例关联到一个特定的控制(除非你动态地创建控制通过调用create()成员函数从CImageButtonWithStyle实例)。 演示应用程序 演示应用程序是使用Visual Studio应用程序向导生成的。我创建了一个最小的SDI应用程序,并添加了一个菜单命令“View|View Dialog…”来调用本文顶部显示的示例对话框。 引擎盖下面 我从MFC CButton类派生了新的CImageButtonWithStyle类,并为NM_CUSTOMDRAW通知添加了一个处理程序。如果一个旧版本的comctl32.dll正在被使用(即pre Windows XP),那么没有NM_CUSTOMDRAW通知将被发送到按钮控件,所以我的处理程序将不会被调用。不需要担心向后兼容性,因为在这种情况下新代码不是活动的。 我没有直接调用uxtheme.dll visual styles API函数,而是使用David A. Zhao的文章Add中的CVisualStylesXP类XP Visual Style支持OWNERDRAW控件动态加载uxtheme.dll。当运行在没有uxtheme.dll的旧Windows版本上时,CVisualStylesXP无法加载这个库,所以它提供了总是失败的函数的存根版本。如果我直接调用uxtheme.dll函数,使用CImageButtonWithStyle的应用程序将无法加载到旧版本的Windows上。 NM_CUSTOMDRAW处理程序OnNotifyCustomDraw()被传递一个指向NMCUSTOMDRAW结构的指针。CImageButtonWithStyle处理程序做以下工作: 如果按钮控件没有BS_ICON或BS_BITMAP设置的样式标志,或者没有使用XP可视化样式主题,则处理程序简单地返回CDRF_DODEFAULT。这会导致默认的窗口程序(由comctl32.dll提供)渲染按钮,就像它通常会(就像如果我没有处理NM_CUSTOMDRAW在第一个地方)。 如果NMCUSTOMDRAW结构的dwDrawStage成员的值是CDDS_PREERASE,则通过调用CVisualStylesXP全局实例g_xpStyle的DrawThemeParentBackground()成员来擦除背景。 通过调用g_xpStyle.OpenThemeData()获得XP visual styles主题数据的句柄。 使用按钮的窗口样式和NMCUSTOMDRAW结构的uItemState成员来确定用于绘制背景的按钮状态:PBS_DISABLED、PBS_PRESSED、PBS_HOT、PBS_DEFAULTED或PBS_NORMAL,然后使用g_xpStyle.DrawThemeBackground()绘制它。 从g_xpStyle.GetThemeBackgroundContentRect()获得描述按钮图像内部的矩形。 使用g_xpStyle.CloseThemeData()关闭主题句柄。 使用按钮样式位BS_LEFT、BS_RIGHT、BS_TOP和BS_BOTTOM来确定图像位置,然后使用Windows DrawState()函数绘制位图或图标图像(如果按钮的窗口样式包含WS_DISABLED标志,则传递DSS_DISABLED标志)。 如果uItemState包含CDIS_FOCUS标志,则调用DrawFocusRect()在边框内绘制焦点矩形。 最后,将返回结果设置为CDRF_SKIPDEFAULT,以告诉默认窗口过程(来自comctl32.dll)不绘制按钮(因为我的代码已经绘制了)。 本文转载于:http://www.diyabc.com/frontweb/news830.html

原文地址:https://www.cnblogs.com/Dincat/p/13456138.html