按钮贴图2

★5--2--4 按钮的自绘制
前面讲述的三种在按钮上显示图像的方法或多或少的存在着不足之处,图标按钮太小,位图按钮无法设置透明色,CBitmapButton 类位图按钮位图大小不能随按钮控件变化。使用按钮的自绘制技术是解决以上问题的最佳途径。当然,按钮的自绘制技术的作用不仅仅局限于按钮表面显示图像,利用它可以充分发挥自己的创造力从而创建出各式各样的按钮控件。例如动画按钮等。如果说利用按钮自绘制技术在按钮上显示图像唯一有一点不足的话,那就是实现略为复杂了一些。但利用按钮自绘制技术,在配合以 DIB 文件读取技术,就完全能够实现象 Winamp 中那样的 Skin 技术。
概念解释:
先解释一下什么叫做按钮的自绘制,准确的说应该是控件的自绘制技术。Windows 能够向控件的父窗口发送消息以让父窗口定制控件的外观和行为。MFC 则更近了一步,它能够译解自绘制参数并将消息发回控件本身。因为绘制控件的代码实在控件类中实现,而不是在拥有控件的窗口中,因而称为“自绘制”。除按钮控件可以自绘制外,列表框、组合框以及菜单都支持自绘制。
在基于对话框的应用程序框架的基础上创建一个自绘制的按钮,主要有以下步骤:
■ 第一步:
在对话框上放置一个按钮,并在其 Properties 中设置 Owner Draw 属性。
■ 第二步:
     用 ClassWizard 从 CButton 类中派生出一个新类。进入 ClassWizard,点击 Message Maps 标签下的 New 按钮,在弹出的菜单中选择 New 命令进入 New Class 对话框。在 New Class 对话框中填入新创建类的名称 CownerDrawBton,以及选择所创建类的父类为 CButton(如下图 5-4):
■ 第三步:
为新创建的 COwnerDrawBton 类增加一个成员函数 DrawItem()。在 WorkSpace 窗口中的 Class View 标签下,右键单击类 COwnerDrawBton,在随后的菜单中选择 Add Virtual Funtion…命令(如左下图 5-5)进入 New Virtual Override for class COwnerDrawBton 对话框(如右下图 5-6),在该对话框的 New Virtual Function 栏中选择函数 DrawItem,再点击 Add and Edit 按钮就超越了函数 DrawItem,并进入其内部处于待编辑状态。
概念解释:
函数 DrawItem():该函数在当自绘制按钮的外观需要重绘时调用。其定义如下:
              virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );
参数 lpDrawItemStruct 为指向结构 DRAWITEMSTRUCT 的一个长指针。结构DRAWITEMSTRUCT 定义如下:
typedef struct tagDRAWITEMSTRUCT {
       UINT      CtlType;
       UINT      CtlID;
       UINT      itemID;
       UINT      itemAction;
       UINT      itemState;
       HWND      hwndItem;
       HDC       hDC;
       RECT      rcItem;
       DWORD     itemData;
} DRAWITEMSTRUCT;
该结构中部分成员变量作用如下:
CtlType:表示控件类型,当为常量 ODT_BUTTON 表示为自绘制按钮。
CtlID :表示控件的 ID。
ItemAction:绘制动作。
ItemState:在当前绘制动作完成后,确定控件所处状态。
HwndItem:控件窗口的句柄。
HDC:设备环境句柄。
RcItem:确定自绘制控件大小的矩形。
通过DRAWITEMSTRUCT结构中的各成员变量,就可以为控件的自绘制提供必要的条件。
■ 第四步:
利用 ClassWizard 中定义一个 COwnerDrawBton 类对象 m_BtonOD(如下图 5-7):注意在 VC++ 中,必须采用这种方式来定义对象 m_BtonOD,如果是在类定义文件中手工定义该对象的话,则不会执行超越的虚函数 DrawItem( )。同样,如果是不定义该对象的话,则不会执行函数DrawItem( )。

■ 第五步:
向函数 DrawItem() 中加入以下代码:
void COwnerDrawBton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: Add your code to draw the specified item
CDC *pDC;
CRect rcBton;
CDC dcMem;
BITMAP s_Bmp;
CBitmap m_Bitmap;
CBitmap *pOldBitmap;
pDC = CDC::FromHandle(lpDrawItemStruct -> hDC);
// 将设备环境句柄转换为指向设备环境的指针
rcBton = lpDrawItemStruct -> rcItem; // 获取按钮控件大小
m_Bitmap.LoadBitmap(IDB_Bmp);      // 载入位图
dcMem.CreateCompatibleDC(pDC);     // 创建于内存设备环境相兼容的设备环境
pOldBitmap = dcMem.SelectObject(&m_Bitmap);
// 将位图对象选入到内存设备环境中
m_Bitmap.GetBitmap(&s_Bmp);        // 获取位图信息
pDC -> StretchBlt(rcBton.left,rcBton.top,rcBton.Width(),rcBton.Height(),
&dcMem,0,0,s_Bmp.bmWidth,s_Bmp.bmHeight,SRCCOPY);
// 将位图从内存设备环境拷贝到显示设备环境
dcMem.SelectObject(pOldBitmap);      // 删除刚才选入到内存设备环境的位图对象
}
在上面的代码只是为了说明如何进行按钮控件的自绘制,它距实用要求还有一段距离。因为在对话框上每个自绘制的按钮控件都会调用 DrawItem( ) 函数。所以在 DrawItem( ) 函数内部,还必须根据结构 DRAWITEMSTRUCT 的成员变量 CtlID 来区分不同的按钮控件,进而再采取不同的操作。同时还需根据按钮控件的不同状态,进行不同的操作。
在上一节中讲述的 CBitmapButton 类实际上也是通过对按钮控件进行自绘制而实现的。但是在向按钮上绘制图像时它是采用函数 BitBlt( ),而不是使用函数 StretchBlt( ),因而造成 CBitmapButton 类位图按钮上的位图大小不会随控件大小改变而改变。根据这一原理,我们自己创建一个与 CBitmapButton 作用和使用方法相似类 CBmpBton,它也可以使用四幅不同的位图来表示按钮不同的状态,位图的命名原则同 CBitmapButton 完全一致。不同的是,它无需使用诸如 AutoLoad( ) 一类的函数来加载位图。的其他部分同上面的 COwnerDrawBton 完全一致,只不过是函数 DrawItem( ) 的实现不同,下面就是类 CBmpBton 的 DrawItem( ) 函数的实现代码:
void CBmpBton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
CRect rcBton;
CDC *pDC;
UINT action;
UINT CtrID;
CString strCaption;
CBitmap m_Bitmap;
CBitmap *pOldBitmap;
CDC dcMem;
BITMAP s_Bmp;
rcBton.CopyRect(&lpDIS -> rcItem);
pDC = CDC::FromHandle(lpDIS -> hDC);
state = lpDIS -> itemState;
action = lpDIS -> itemAction;
CtrID = lpDIS -> CtlID;
GetWindowText(strCaption);
// GetDlgItemText(CtrID,strCaption);
dcMem.CreateCompatibleDC(pDC);
if(state == 16)
{
if(m_Bitmap.LoadBitmap(strCaption + _T("F")))
{
pOldBitmap = dcMem.SelectObject(&m_Bitmap);
m_Bitmap.GetBitmap(&s_Bmp);
pDC -> StretchBlt(rcBton.left,rcBton.top,rcBton.Width(),rcBton.Height(),
&dcMem,0,0,s_Bmp.bmWidth,s_Bmp.bmHeight,SRCCOPY);
}
else
{
if(m_Bitmap.LoadBitmap(strCaption + _T("U")))
{
pOldBitmap = dcMem.SelectObject(&m_Bitmap);
m_Bitmap.GetBitmap(&s_Bmp);
pDC->StretchBlt(rcBton.left,rcBton.top,rcBton.Width(),rcBton.Height(),
&dcMem,0,0,s_Bmp.bmWidth,s_Bmp.bmHeight,SRCCOPY);
}
else
{
TRACE("必须载入一副位图");
}
}
}
else if(state == 4)
{
if(m_Bitmap.LoadBitmap(strCaption + _T("X")))
{
pOldBitmap = dcMem.SelectObject(&m_Bitmap);
m_Bitmap.GetBitmap(&s_Bmp);
pDC -> StretchBlt(rcBton.left,rcBton.top,rcBton.Width(),rcBton.Height(),
&dcMem,0,0,s_Bmp.bmWidth,s_Bmp.bmHeight,SRCCOPY);
}
}
else if(state & ODS_SELECTED)
{
if(m_Bitmap.LoadBitmap(strCaption + _T("D")))
{
pOldBitmap = dcMem.SelectObject(&m_Bitmap);
m_Bitmap.GetBitmap(&s_Bmp);
pDC -> StretchBlt(rcBton.left,rcBton.top,rcBton.Width(),rcBton.Height(),
&dcMem,0,0,s_Bmp.bmWidth,s_Bmp.bmHeight,SRCCOPY);
}
}
else
{
if(m_Bitmap.LoadBitmap(strCaption + _T("U")))
{
pOldBitmap = dcMem.SelectObject(&m_Bitmap);
m_Bitmap.GetBitmap(&s_Bmp);
pDC -> StretchBlt(rcBton.left,rcBton.top,rcBton.Width(),rcBton.Height(),
            &dcMem,0,0,s_Bmp.bmWidth,s_Bmp.bmHeight,SRCCOPY);
}
else
{
TRACE("必须载入一副位图 U");
}
}
dcMem.SelectObject(pOldBitmap);

{}
文章出处:http://www.diybl.com/course/3_program/c++/cppsl/200889/135322.html

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值