之前一直使用公司开发的界面库来进行VC界面设计,今天偶然发现其中一个按钮类不能实现特定需求,例如文字的位置不能随意显示在按钮上。于是唯有重新定义了该按钮类的自绘功能,添加新的属性和操作。
通过这次修改,感觉控件自绘也还是蛮有意思的,本来不能实现的功能,通过类的派生和自绘就能实现,感觉真爽,符合人性欲望无限扩展的本性。
说起VC的界面设计,大家都应该很清楚,MFC提供了很多标准的控件,例如按钮,下拉框等等,但是这些控件本身并不美观。要想改变它们的形状和外观,就必须要进行控件的自绘。我们常常看到QQ,360的界面设计,之所以那么狂吊炸天,就是因为他们有自己的界面库,能实现控件的自绘。现以一个简单的例子来介绍按钮自绘的方法实现。(部分函数代码和实现原理还是要列出的,因为代码才是王道啊,步骤就略过哈。)
1. 功能需求
1) 实现按钮文字任意位置的偏移。效果图如下:
2) 实现按钮的几种状态
Normal:
Over:
Down:
Disable:
2. 方法实现
首先定义一个CSkinButton类,它继承于CButton类。
1) 自绘属性
要想实现按钮自绘,需要把按钮风格修改为自绘属性BS_OWNERDRAW,从而系统会发送WM_DRAWITEM消息给CButton类,才会调用重载函数DrawItem实现自绘。可选择在对话框属性中或者在重载函数PreSubclassWindow中添加ModifyStyle(0,BS_OWNERDRAW);。
void CSkinButton::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
ModifyStyle(0,BS_OWNERDRAW);
CButton::PreSubclassWindow();
}
2) 重载DrawItem()函数
DrawItem()函数主要是根据按钮的状态来绘制自身的形状和外观,按钮控件自绘的功能就是在这里实现的。它主要包含了一个LPDRAWITEMSTRUCT的指针。声明如下:
typedef struct tagDRAWITEMSTRUCT {
UINT CtlType; //控件的类型
UINT CtlID; //自绘控件ID
UINT itemID; //菜单项ID
UINT itemAction; //绘制行为
UINT itemState; //当前绘制操作完成后,所绘项的可见状态
HWND hwndItem; //指定了组合框、列表框和按钮等自绘控件的窗口句柄
HDC hDC; //绘制操作所使用的设备环境
RECT rcItem; //绘制的矩形区域。这个区域就是上面hDC的作用范围。
ULONG_PTR itemData; //菜单项数据
} DRAWITEMSTRUCT, NEAR *PDRAWITEMSTRUCT, FAR *LPDRAWITEMSTRUCT
具体实现如下:
void CSkinButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: Add your code to draw the specified item
CRect rcItem(lpDrawItemStruct->rcItem);
CString strText,strPath;
CString strWorkPath;
//按钮状态
int nStatus = CONTROL_STATUS_NORMAL;
if ( !IsWindowEnabled() )
{
nStatus = CONTROL_STATUS_DISABLE;
}
else
{
if ( m_bTrackMouseEvent )
{
if ( m_bLButtonDown )
{
nStatus = CONTROL_STATUS_DOWN;
}
else
{
nStatus = CONTROL_STATUS_OVER;
}
}
else
{
// if ( ::GetFocus()==m_hWnd )
// {
// nStatus = CONTROL_STATUS_FOCUS;
// }
// else
{
nStatus = CONTROL_STATUS_DISABLE/*CONTROL_STATUS_NORMAL*/;
}
}
}
if ( m_hBitmap[nStatus] )
{
//绘图
Draw9gridTransparent(lpDrawItemStruct->hDC, lpDrawItemStruct->rcItem, m_rcBorder9grid, m_hBitmap[nStatu