自己动手做按钮
作者:风林
现在网上发布的自制按钮很多,实际上其制作方法都很类似,以下给出几个关键步骤,具体细节你大可以发挥你的想象力,制作出你想要的各种按钮。
一、用ClassWizard生成一个新类,名字假设起为CMyButton,基类选为CButton;
二、在新类中用ClassWizard添加函数:PreSubclassWindow()、DrawItem()、OnMouseMove()、OnLButtonDown()、OnLButtonUp();
① PreSubclassWindow()函数在绘制按钮前执行,在这里我只做了一个工作:
void CMyButton::PreSubclassWindow()
{
CButton::PreSubclassWindow();
ModifyStyle( 0 , BS_OWNERDRAW ); // 设置按钮属性为自画式
}
这样你就无需在放置按钮时非得设置按钮属性为“OwnerDraw”了。
② DrawItem()函数是最重要的函数,所有自己绘制按钮的工作都在这里进行,它的作用类似于View类中的OnDraw()函数。
例:
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC * pDC = CDC::FromHandle( lpDrawItemStruct -> hDC );
m_ButRect = lpDrawItemStruct -> rcItem; // 获取按钮尺寸
GetWindowText( m_strText ); // 获取按钮文本
CPoint m_ptCentre = m_ButRect.CenterPoint(); // 求按钮中心点
CSize Extent = pDC -> GetTextExtent( m_strText ); // 求文本尺寸
m_textPt = CPoint( m_ptCentre.x - Extent.cx / 2 ,
m_ptCentre.y - Extent.cy / 2 ); // 设置文本坐标
int nSavedDC = pDC -> SaveDC();
VERIFY( pDC );
if ( ! (::GetWindowLong(m_hWnd,GWL_STYLE) & WS_DISABLED) )
{
if ( ! b_Flag )
{
NormalButton( pDC ); // 画正常按钮
}
else
{
PassButton( pDC ); // 画鼠标经过时的按钮
}
}
else
{
LockButton( pDC ); // 画锁定的按钮
}
pDC -> RestoreDC( nSavedDC );
}
其中的变量在CMyButton.h中定义:
BOOL b_Flag; // 按钮状态(false-正常,true-当前)
BOOL b_InRect; // 鼠标进入标志
CString m_strText; // 按钮文字
COLORREF m_ForeColor; // 文本颜色
COLORREF m_BkColor; // 背景色
COLORREF m_LockForeColor; // 锁定按钮的文字颜色
CRect m_ButRect; // 按钮尺寸
CPoint m_textPt; // 文字坐标(左上角)
具体绘制按钮的函数是另外定义的,只要你会用VC绘图,就可随心所欲的画出你想要的任何形态按钮,这里我定义了三种情况的按钮:
绘制正常状态下的按钮:
void CMyButton::NormalButton(CDC * pDC)
{
……
}
绘制鼠标进入按钮区域后的按钮:
void CMyButton::PassButton(CDC * pDC)
{
……
}
绘制锁定(变灰)状态下的按钮:
void CMyButton::LockButton(CDC * pDC)
{
……
}
有些人还希望绘制“鼠标按下时的按钮”、“拥有焦点的按钮”使效果更好,可在相应位置做如下修改:
int b_Flag; // 0-正常、1-鼠标进入、2-鼠标按下、3-拥有焦点
switch (b_Flag)
{
case 0 :画正常按钮; break ;
case 1 :画鼠标进入后的按钮; break ;
case 2 :画鼠标按下后的按钮; break ;
case 3 :画拥有焦点的按钮; break ;
}
而b_Flag的值在鼠标消息函数中进行修改。
③ OnMouseMove()函数用于判定鼠标是否在按钮上:
void CMyButton::OnMouseMove(UINT nFlags, CPoint point)
{
CButton::OnMouseMove(nFlags, point);
if ( ! b_InRect || GetCapture() != this ) // 鼠标进入按钮
{
b_InRect = true ;
SetCapture();
b_Flag = true ;
Invalidate(); // 重绘按钮
}
else
{
CRect rc;
this -> GetClientRect( & rc );
if ( ! rc.PtInRect(point) ) // 鼠标离开按钮
{
b_InRect = false ;
ReleaseCapture();
b_Flag = false ;
Invalidate(); // 重绘按钮
}
}
}
变量b_InRect用于判定鼠标是进入了按钮区还是从按钮中离开,b_Flag决定了绘制何种按钮,Invalidate()函数调用DrawItem()函数重绘按钮。
④ OnLButtonDown()函数和OnLButtonUp()函数与OnMouseMove()函数类似,用于鼠标按下和弹起时重绘按钮。
void CMyButton::OnLButtonDown(UINT nFlags, CPoint point)
{
b_Flag = false ;
if (GetFocus() != this )
{
this -> SetFocus();
}
CButton::OnLButtonDown( nFlags, point );
Invalidate(); // 重绘按钮
}
本例中我在鼠标按下时绘制的是“正常状态”的按钮。
void CMyButton::OnLButtonUp(UINT nFlags, CPoint point)
{
b_Flag = true ;
if (GetFocus() != this )
{
this -> SetFocus();
}
CButton::OnLButtonUp( nFlags, point );
Invalidate(); // 重绘按钮
}
我在鼠标弹起后绘制的是“鼠标进入按钮区状态”的按钮。
三、在CMyButton类的构造函数中设置变量的初值:
CMyButton::CMyButton()
{
b_InRect = false ;
b_Flag = false ;
}
这样一个新的按钮类的核心部分就完成了,你还可以根据需要再设计一些接口函数,如设置按钮颜色、设置按钮状态等,使得调用时更灵活方便。
在我提供的示例程序中,我仿造Dreamweaver的界面制作了几个按钮类,你用我上面提供的方法看一看,应该容易看得懂,再自己发挥一下应该能设计你所需要的按钮了。
作者:风林
现在网上发布的自制按钮很多,实际上其制作方法都很类似,以下给出几个关键步骤,具体细节你大可以发挥你的想象力,制作出你想要的各种按钮。
一、用ClassWizard生成一个新类,名字假设起为CMyButton,基类选为CButton;
二、在新类中用ClassWizard添加函数:PreSubclassWindow()、DrawItem()、OnMouseMove()、OnLButtonDown()、OnLButtonUp();
① PreSubclassWindow()函数在绘制按钮前执行,在这里我只做了一个工作:
void CMyButton::PreSubclassWindow()
{
CButton::PreSubclassWindow();
ModifyStyle( 0 , BS_OWNERDRAW ); // 设置按钮属性为自画式
}
这样你就无需在放置按钮时非得设置按钮属性为“OwnerDraw”了。
② DrawItem()函数是最重要的函数,所有自己绘制按钮的工作都在这里进行,它的作用类似于View类中的OnDraw()函数。
例:
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC * pDC = CDC::FromHandle( lpDrawItemStruct -> hDC );
m_ButRect = lpDrawItemStruct -> rcItem; // 获取按钮尺寸
GetWindowText( m_strText ); // 获取按钮文本
CPoint m_ptCentre = m_ButRect.CenterPoint(); // 求按钮中心点
CSize Extent = pDC -> GetTextExtent( m_strText ); // 求文本尺寸
m_textPt = CPoint( m_ptCentre.x - Extent.cx / 2 ,
m_ptCentre.y - Extent.cy / 2 ); // 设置文本坐标
int nSavedDC = pDC -> SaveDC();
VERIFY( pDC );
if ( ! (::GetWindowLong(m_hWnd,GWL_STYLE) & WS_DISABLED) )
{
if ( ! b_Flag )
{
NormalButton( pDC ); // 画正常按钮
}
else
{
PassButton( pDC ); // 画鼠标经过时的按钮
}
}
else
{
LockButton( pDC ); // 画锁定的按钮
}
pDC -> RestoreDC( nSavedDC );
}
其中的变量在CMyButton.h中定义:
BOOL b_Flag; // 按钮状态(false-正常,true-当前)
BOOL b_InRect; // 鼠标进入标志
CString m_strText; // 按钮文字
COLORREF m_ForeColor; // 文本颜色
COLORREF m_BkColor; // 背景色
COLORREF m_LockForeColor; // 锁定按钮的文字颜色
CRect m_ButRect; // 按钮尺寸
CPoint m_textPt; // 文字坐标(左上角)
具体绘制按钮的函数是另外定义的,只要你会用VC绘图,就可随心所欲的画出你想要的任何形态按钮,这里我定义了三种情况的按钮:
绘制正常状态下的按钮:
void CMyButton::NormalButton(CDC * pDC)
{
……
}
绘制鼠标进入按钮区域后的按钮:
void CMyButton::PassButton(CDC * pDC)
{
……
}
绘制锁定(变灰)状态下的按钮:
void CMyButton::LockButton(CDC * pDC)
{
……
}
有些人还希望绘制“鼠标按下时的按钮”、“拥有焦点的按钮”使效果更好,可在相应位置做如下修改:
int b_Flag; // 0-正常、1-鼠标进入、2-鼠标按下、3-拥有焦点
switch (b_Flag)
{
case 0 :画正常按钮; break ;
case 1 :画鼠标进入后的按钮; break ;
case 2 :画鼠标按下后的按钮; break ;
case 3 :画拥有焦点的按钮; break ;
}
而b_Flag的值在鼠标消息函数中进行修改。
③ OnMouseMove()函数用于判定鼠标是否在按钮上:
void CMyButton::OnMouseMove(UINT nFlags, CPoint point)
{
CButton::OnMouseMove(nFlags, point);
if ( ! b_InRect || GetCapture() != this ) // 鼠标进入按钮
{
b_InRect = true ;
SetCapture();
b_Flag = true ;
Invalidate(); // 重绘按钮
}
else
{
CRect rc;
this -> GetClientRect( & rc );
if ( ! rc.PtInRect(point) ) // 鼠标离开按钮
{
b_InRect = false ;
ReleaseCapture();
b_Flag = false ;
Invalidate(); // 重绘按钮
}
}
}
变量b_InRect用于判定鼠标是进入了按钮区还是从按钮中离开,b_Flag决定了绘制何种按钮,Invalidate()函数调用DrawItem()函数重绘按钮。
④ OnLButtonDown()函数和OnLButtonUp()函数与OnMouseMove()函数类似,用于鼠标按下和弹起时重绘按钮。
void CMyButton::OnLButtonDown(UINT nFlags, CPoint point)
{
b_Flag = false ;
if (GetFocus() != this )
{
this -> SetFocus();
}
CButton::OnLButtonDown( nFlags, point );
Invalidate(); // 重绘按钮
}
本例中我在鼠标按下时绘制的是“正常状态”的按钮。
void CMyButton::OnLButtonUp(UINT nFlags, CPoint point)
{
b_Flag = true ;
if (GetFocus() != this )
{
this -> SetFocus();
}
CButton::OnLButtonUp( nFlags, point );
Invalidate(); // 重绘按钮
}
我在鼠标弹起后绘制的是“鼠标进入按钮区状态”的按钮。
三、在CMyButton类的构造函数中设置变量的初值:
CMyButton::CMyButton()
{
b_InRect = false ;
b_Flag = false ;
}
这样一个新的按钮类的核心部分就完成了,你还可以根据需要再设计一些接口函数,如设置按钮颜色、设置按钮状态等,使得调用时更灵活方便。
在我提供的示例程序中,我仿造Dreamweaver的界面制作了几个按钮类,你用我上面提供的方法看一看,应该容易看得懂,再自己发挥一下应该能设计你所需要的按钮了。