制作風格獨特的按鈕—用VC6擴展CButton類
發表于:2007-07-14來源:作者:點擊數:
標簽:
一、 本文介紹一個CButton的派生類CLinkButton,用此派生類制作的按鈕具有以下特點: 1、按鈕的外觀類似靜態控件類CStatic 產生的對象。 2、當鼠標的光標移到按鈕上,但并未按下時,光標改變形狀,字體改變形狀;按鈕類似應用在工具條和菜單上的扁平鈕效果
一、 本文介紹一個CButton的派生類CLinkButton,用此派生類制作的按鈕具有以下特點:
1、按鈕的外觀類似靜態控件類CStatic 產生的對象。
2、當鼠標的光標移到按鈕上,但并未按下時,光標改變形狀,字體改變形狀;按鈕類似應用在工具條和菜單上的扁平鈕效果
二、下面具體描述這種按鈕的實現方法和步驟:
1. 在VC6的IDE環境中,生成一個基于對話框的PROJECT。
2. 將對話框資源中按鈕的屬性頁打開,在“Style”標簽頁中選取按鈕的“Owner Draw”(自繪)屬性。
3. 將光標引入到應用程序的資源中。
4. 利用CLASSWIZARD,用CButton為基類,派生一個新類:CLinkButton。
5. 在派生類中重載基類CButton的虛函數:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
之所以要重載這個函數是因為選擇了按鈕的 “Owner Draw”屬性后,當按鈕的可視行為發生變化時,應用程序的框架要調用這個函數來重新繪制按鈕。
6. 定制以下的消息處理:
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
7. 聲明類成員變量定義:
//定義字體變量
CFont fUnderline;
//定義光標變量
HCURSOR hHand;
//決定按鈕是否按下
bool bLBtnDown;
//決定鼠標是否在按鈕上
bool bHighlight;
二、 派生類CLinkButton 的具體實現:
1.重載函數 DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)。
void CLinkButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// 獲取一個CDC指針
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
//定義按鈕區域并初始化
CRect rect(lpDrawItemStruct->rcItem);
//設置背景模式
COLORREF oc = pDC->GetTextColor();
int iObk = pDC->SetBkMode(TRANSPARENT);
//初始化按鈕狀態
UINT state = lpDrawItemStruct->itemState;
CFont * pOldFont = NULL;
int iYOffset = 0, iXOffset = 0;
CString strText;
GetWindowText(strText);
rect.top += iYOffset;
rect.left += iXOffset;
if (state & ODS_DISABLED)
{
//按鈕置灰狀態(DISABLED)
CBrush grayBrush;
grayBrush.CreateSolidBrush (GetSysColor (COLOR_GRAYTEXT));
CSize sz = pDC->GetTextExtent(strText);
int x = rect.left + (rect.Width() - sz.cx)/2;
int y = rect.top + (rect.Height() - sz.cy)/2;
rect.top += 2;
rect.left += 2;
pDC->SetTextColor(GetSysColor(COLOR_3DHIGHLIGHT));
pDC->DrawText(strText, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
rect.top -= 2;
rect.left -= 2;
pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
pDC->DrawText(strText, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
else
{
if (bHighlight)//光標在按鈕上
{
if (state & ODS_SELECTED)
{
//按下按鈕
pDC->Draw3dRect(rect,GetSysColor(COLOR_3DSHADOW),
GetSysColor(COLOR_3DHILIGHT));
}
else
{//未按下按鈕
pDC->Draw3dRect(rect,GetSysColor(COLOR_3DHILIGHT),
GetSysColor(COLOR_3DSHADOW));
}
//字體顏色
pDC->SetTextColor(RGB(0,0,255));
//加下畫線(也可以用其他字體)
if (fUnderline.GetSafeHandle() == NULL)
{
CFont * pFont = GetFont();
ASSERT(pFont);
LOGFONT lf;
pFont->GetLogFont(&lf);
lf.lfUnderline = TRUE;
fUnderline.CreateFontIndirect(&lf);
}
pOldFont = pDC->SelectObject(&fUnderline);
}
else pDC->SetTextColor(GetSysColor(COLOR_BTNTEXT));
pDC->DrawText(strText, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
if (pOldFont) pDC->SelectObject(pOldFont);
}
}
2.定制的消息處理函數
void OnMouseMove(UINT nFlags, CPoint point)
{
//設置一個定時器
SetTimer(1,10,NULL);
//
...
}
當鼠標光標移到按鈕上時,執行此函數,定時器將發送一個 WM_TIMER消息到消息隊列。
由OnTimer(UINT nIDEvent)函數處理這個消息。
void OnTimer(UINT nIDEvent)
{
//處理WM_TIMER消息
static bool pPainted = false;
POINT pt;
GetCursorPos(&pt);
CRect rect;
GetWindowRect (rect);
if (bLBtnDown)
{
KillTimer (1);
if (pPainted) InvalidateRect (NULL);
pPainted = FALSE;
return;
}
if (!rect.PtInRect (pt))
{
bHighlight = false;
KillTimer (1);
if (pPainted)
InvalidateRect(NULL);
pPainted = false;
return;
}
else
{
bHighlight = true;
if (!pPainted)
{
pPainted = true;
InvalidateRect(NULL);
}
}
//
CButton::OnTimer(nIDEvent);
}
BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
//當鼠標光標移到按鈕上時,改變光標的形象
if (bHighlight)
{
::SetCursor(hHand);
return true;
}
//
...
}
int OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
CFont * pFont = GetFont();
ASSERT(pFont);
LOGFONT lf;
pFont->GetLogFont(&lf);
lf.lfUnderline = TRUE;
fUnderline.CreateFontIndirect(&lf);
...
}
這個函數由框架在顯示出按鈕之前自動調用,我在這里初始化在按鈕上顯示的字體。
void OnLButtonUp(UINT nFlags, CPoint point)
{
bLBtnDown = false;
if (bHighlight)
{
bHighlight = false;
InvalidateRect(NULL);
}
...
}
當按下按鈕又放開時調用這個函數。
void OnLButtonDown(UINT nFlags, CPoint point)
{
bLBtnDown = true;
...
}
當按下按鈕時調用這個函數。
BOOL OnEraseBkgnd(CDC* pDC)
{
COLORREF cr = GetSysColor(COLOR_3DFACE);
int r = GetRValue(cr);
int g = GetGValue(cr);
int b = GetBValue(cr);
if (r > 1) r -= 2;
if (g > 1) g -= 2;
if (r <3 && g < 3 && b < 253) b +=2;
COLORREF cr1 = RGB(r,g,b);
CRect rc;
GetClientRect(rc);
pDC->FillSolidRect(rc, cr1);
...
}
當按鈕的背景需要重畫時,應用程序框架調用此函數。編譯并運行PROJECT LinkBtn
原文轉自:http://www.kjueaiud.com