程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 用VC6擴展CButton類制作風格獨特的按鈕

用VC6擴展CButton類制作風格獨特的按鈕

編輯:關於VC++

一、 本文介紹一個CButton的派生類CLinkButton,用此派生類制作的按鈕具有以下特點:

1、按鈕的外觀類似靜態控件類CStatic 產生的對象。(參見圖一)

圖一

2、當鼠標的光標移到按鈕上,但並未按下時,光標改變形狀,字體改變形狀;按鈕類似應用在工具條和菜單上的扁平鈕效果。(參見圖二)

圖二

3、當按鈕按下的情形:(參見圖三)

圖三

二、下面具體描述這種按鈕的實現方法和步驟:

  • 在VC6的IDE環境中,生成一個基於對話框的PROJECT。
  • 將對話框資源中按鈕的屬性頁打開,在“Style”標簽頁中選取按鈕的“Owner Draw”(自繪)屬性。
  • 將光標引入到應用程序的資源中。
  • 利用CLASSWIZARD,用CButton為基類,派生一個新類:CLinkButton。
  • 在派生類中重載基類CButton的虛函數: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)   之所以要重載這個函數是因為選擇了按鈕的 “Owner Draw”屬性後,當按鈕的可視行為發生變化時,應用程序的框架要調用這個函數來重新繪制按鈕。
  • 定制以下的消息處理: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);
  • 聲明類成員變量定義: //定義字體變量
       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 CLinkButton::OnMouseMove(UINT nFlags, CPoint point)
{
  //設置一個定時器
  SetTimer(1,10,NULL);
  CButton::OnMouseMove(nFlags, point);
}   
  當鼠標光標移到按鈕上時,執行此函數,定時器將發送一個 WM_TIMER消息到消息隊列。由OnTimer(UINT nIDEvent)函數處理這個消息。 void CLinkButton::OnTimer(UINT nIDEvent)
{
  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 CLinkButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
  if (bHighlight)
  {
    ::SetCursor(hHand);
    return true;
  }
  return CButton::OnSetCursor(pWnd, nHitTest, message);
}
int CLinkButton::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
  if (CButton::OnCreate(lpCreateStruct) == -1)
    return -1;
  CFont * pFont = GetFont();
  ASSERT(pFont);
  LOGFONT lf;
  pFont->GetLogFont(&lf);
  lf.lfUnderline = TRUE;
  fUnderline.CreateFontIndirect(&lf);
  return 0;
}   
這個函數由框架在顯示出按鈕之前自動調用,我在這裡初始化按鈕上顯示的字體。 void CLinkButton::OnLButtonUp(UINT nFlags, CPoint point)
{
  bLBtnDown = false;
  if (bHighlight)  
  {
    bHighlight = false;
    InvalidateRect(NULL);
  }
  CButton::OnLButtonUp(nFlags, point);
}   
當按下按鈕又放開時調用這個函數。 void CLinkButton::OnLButtonDown(UINT nFlags, CPoint point)
{
  bLBtnDown = true;
  CButton::OnLButtonDown(nFlags, point);
}   
當按下按鈕時調用這個函數。 BOOL CLinkButton::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);
  return CButton::OnEraseBkgnd(pDC);
}  
當按鈕的背景需要重畫時,應用程序框架調用此函數。

其他實現細節請下載源代碼。運行程序的效果圖見圖一、圖二和圖三。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved