科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件WTL自画按钮的实现

WTL自画按钮的实现

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

Windows 为控件提供了自画(owner draw)的能力,可以通过这一机制可以实现非常酷的控件外观。

作者:Bjarne 来源:yesky 2007年10月22日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
三、CBitmapButtonImpl模板

  CbitmapButtonImpl为位图按钮提供了支持,使我们不必了解太多实现细节,就可以做漂亮的位图按钮。它还提供了对ToolTip的支持。我们还可以通过重载DoPaint函数来实现个性化。CbitmapButtonImpl定义了一个重要的成员变量m_ImageList,这个成员主要用于位图或图标的管理和绘制。我们将在例程中看到它的使用方法。

  四、COwnerDrawButton 类

  前面曾经说过,CownerDrawButton类可以通过基类链接的机制,将消息导向其基类,但是如果简单地使用CHAIN_MSG_MAP(CbitmapButtonImpl<CownerDrawButton>) 宏,就会出现问题。因为我们实现是的“自画”按钮,所有的绘制工作都应该在DrawItem函数里完成,但是CbitmapButtonImpl并不知道这种情况,所以它仍然响应WM_PAINT、WM_PRINTCLIENT 和WM_ERASEBKGND以及其它有关绘制操作的消息,并调用DoPaint等函数进行绘制工作,可想而知这会造成极大的混乱。因此我们必须屏蔽掉CownerDrawButton对这些消息的响应。拷贝CbitmapButtonImpl的所有消息映射表项到CownerDrawButton的消息消息映射表中,然后删除这三行:

MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)

MESSAGE_HANDLER(WM_PAINT, OnPaint)

MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)

  再添加CHAIN_MSG_MAP_ALT(COwnerDraw<COwnerDrawButton>,1)这一项,这样窗口默认的绘制消息就不会被触发,问题也得到了解决。但是不要忘记,CownerDrawButton也是一个位图按钮,而CbitmapButtonImpl是在DoPaint函数中实现位图的显示,如果不响应WM_PAINT或者WM_PAINTCLIENT消息,DoPaint是不会被调用的。显然如果CownerDrawButton的m_ImageList成员包含图片的话,我们就需要自己在DrawItem函数里实现位图的显示,当然我们也可以在需要显示位图的时候简单地调用DoPaint函数,只要为它传递一个CDCHandle,DoPaint就会非常好地完成任务,实际上我就是这么做的。不过要想实现图1所显示的按钮,CbitmapButtonImpl提供的DoPaint函数是没有办法办到的。为CownerDrawButton声明一个成员变量m_uBmpPosStyle,当m_ImageList包含图像时,这个变量就被设置,用于存储图像的具体位置。图像的位置被声明为五个无符号的整型常量如下所示:

unsigned int const IMAGEPOS_TOP   = 1 ;

unsigned int const IMAGEPOS_BOTTOM = 2 ;

unsigned int const IMAGEPOS_LEFT  = 3 ;

unsigned int const IMAGEPOS_RIGHT  = 4 ;

unsigned int const IMAGEPOS_CENTER  = 5 ;

  只有当m_ImageList包含图像,图像的扩展样式不是自动尺寸(BMPBTN_AUTOSIZE),并且图像尺寸小于按钮客户区域时,这些样式才有效。还要声明一个CRect类型的成员变量m_ClientRect,用于记录客户区域的尺寸,每当我们显示完位图之后,就对m_ClientRect区域进行裁剪,以便于文本的排布。为了应用这些样式,以及对m_ClientRect成员进行修改,必须对DoPaint进行重载。把CbitmapButtonImpl模板的DoPaint源码拷贝到CownerDrawButton的DoPaint中,然后此基础上进行修改。修改后的DoPaint函数对位图尺寸和客户区域进行比较,如果图片尺寸小于客户区域,则再根据m_uBmpPosStyle设置的样式绘制位图,最后对m_ClientRect进行裁剪,以便于文本布局。在DrawItem函数中,通过对m_ImageList 是否包含图片及是否设置主图进行判断,来决定是否调用DoPaint进行图片的显示。如果没有图片则执行缺省的绘制,并在客户区域中央显示文本。

  为了便于位图资源的导入,CownerDrawButton提供了一个LoadImageFromID函数,原型为:

BOOL LoadImageFromID(UINT IDBitmap ,UINT IDMask, const IMGINFOS & imgno);

  其第三个参数是一个自定义类型的结构,包含了按钮的图像列表成员中包含的各个图像的状态信息、图像的尺寸、图像类型标志、图像列表中初始图像个数和最大图像个数等。结构的声明及函数实现如下:

typedef struct _imageinfo{

int Normal ;

int Pushed ;

int Hover ;

int Disabled ;

int cx;

int cy;

UINT flags;

int cInitial;

int cGrow;

}IMAGELISTINFOSTRUCT;

typedef IMAGELISTINFOSTRUCT IMGINFOS;

file://Load bitmap from resource Id

BOOL LoadImageFromID(UINT IDBitmap ,UINT IDMask, const IMGINFOS & imgno)

{

if(!m_ImageList.Create( imgno.cx,imgno.cy,imgno.flags ,imgno.cInitial,imgno.cGrow))

return FALSE;

CBitmap m_Mask,m_bbmp;

if(!m_bbmp.LoadBitmap(IDBitmap))

return FALSE;

if(!m_Mask.LoadBitmap(IDMask))

return FALSE;

if((m_ImageList.Add(m_bbmp,m_Mask) == -1))

return FALSE;

SetImages(imgno.Normal,imgno.Pushed ,imgno.Hover,imgno.Disabled);

return TRUE;

}

  五、例程

  启动VC++6.0,创建一个基于WTL对话框的应用程序,工程名为OwnerDrawDemo创建完成后,打开ClassView,选择CmainDlg,单击鼠标右键,选择Add Member Variable 为CmainDlg类添加一个CownerDrawButton成员变量。打开ResourceView ,在对话框资源模板上添加一个按钮,调整到合适尺寸,ID为IDC_BUTTON1,Caption 为Help 。导入一幅位图和一幅相应的Mask图,修改ID分别为:IDB_BUTTON、IDB_MASK。

  打开FileView,打开OwnerDrawDemo.cpp在其顶部依次添加#include <atlctrlx.h>、

  #include <atlgdi.h> 和 #include <atlmisc.h>。打开maindlg.h文件,在OnInitDialog函数中添加如下代码:

DWORD style =  BMPBTN_AUTO3D_SINGLE|BMPBTN_SHAREIMAGELISTS|

 BMPBTN_HOVER;

 IMGINFOS imgis = {0,1,1,-1,30,30,ILC_COLOR24|ILC_MASK,0,2};

 if(m_Button.LoadImageFromID(IDB_BUTTON,IDB_MASK,imgis))

 {

   m_Button.SetBitmapButtonExtendedStyle(style);

   m_Button.SetBitmapPosStyle(IMAGEPOS_TOP);

 }

 m_Button.SubclassWindow(GetDlgItem(IDC_BUTTON1));

 m_Button.SetToolTipText(_T("WTL_OwnerDrawButton!"));

  现在就可以按F7构建或者Ctrl + F5执行了。

  程序在Windows2000 + VC++6.0 +WTL 7.0 环境下编译通过,在Windows98、Windows 2000及WindowsXP下运行通过。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章