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

設計XP風格的按鈕

編輯:關於VC++

論壇上許多人都在討論如何編寫具有XP風格的界面,其實網上有設計好的類庫,可以直接拿來使用。但這些終歸是別人寫的,能不能轉化成自已的呢。於是筆者就對這些代碼進行研究,算是偷一點吧:)

研究了幾種控件,這裡就把其中最簡單的按鈕控件拿來供大家一起討論。

這是程序的運行效果:

步驟:

1、創建一個派生自CButton的新類CButtonXp

2、重載PreSubClassWindow()函數,在該函數內修改按鈕的風格為自繪制(owner):

添加如下代碼:ModifyStyle(0,BS_OWNERDRAW);

3、因為XP風格按鈕具有鼠標感應的效果,當鼠標移動到按鈕上方時,按鈕的顏色會改變。所以就必須跟蹤鼠標。當鼠標移到按鈕上方時,窗口會收到

WM_MOUSEMOVE消息,但怎麼才能得知鼠標離開按鈕呢?

這裡我們使用 TrackMouseEvent() Api函數:

BOOL TrackMouseEvent( LPTRACKMOUSEEVENT lpEventTrack );

參數:

typedef struct tagTRACKMOUSEEVENT {

DWORD cbSize; //結構大小

DWORD dwFlags; //設定為TME_LEAVE

HWND hwndTrack; //要跟蹤鼠標的窗口句柄

DWORD dwHoverTime;} TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT;

調用該函數可以在鼠標離開指定窗口時收到WM_MOUSELEAVE消息。

添加成員變量:m_bOver ,初始化為FALSE。m_bOver=true用來表示鼠標在按鈕區域。

添加WM_MOUSEMOVE消息處理函數:

void CButtonXp::OnMouseMove(UINT nFlags, CPoint point)
{
  if(m_bOver ==FALSE)
  {
    //鼠標在按鈕之上
    m_bOver =TRUE;
    //按鈕重繪
    InvalidateRect(NULL,FALSE);
    //跟蹤鼠標
    //當鼠標離開按鈕區域會收到WM_MOUSELEAVE,該消息直接調用OnMouseOut()
    TRACKMOUSEEVENT  tme;
    tme.cbSize =sizeof(TRACKMOUSEEVENT);
    tme.dwFlags =TME_LEAVE;
    tme.dwHoverTime=0;
    tme.hwndTrack =m_hWnd;
    ::TrackMouseEvent(&tme);
  }
  CButton::OnMouseMove(nFlags, point);
}

再添加一成員函數OnMouseOut(),

並在BEGIN_MESSAGE_MAP(CButtonXp, CButton)和END_MESSAGE_MAP()之間添加

宏 ON_MESSAGE(WM_MOUSELEAVE,OnMouseOut)

在OnMouseOut()中寫入以下代碼

void CButtonXp::OnMouseOut ()
{
  //鼠標已離開按鈕區域
  m_bOver =FALSE;
  //重繪按鈕
  InvalidateRect(NULL,FALSE);
}

4、添加成員函數 MouseOver()

//返回鼠標是否在按鈕區域內
BOOL CButtonXp::MouseOver()
{
  return m_bOver;
}

5、最後重載DrawItem(LPDRAWITEMSTRUCT lpDIS)

void CButtonXp::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
  CDC  *pDC =CDC::FromHandle(lpDIS->hDC);
  CRect  rtControl(lpDIS->rcItem);
  CPen  pen,*old_pen;
  CBrush  brush,*old_brush;
  CString strText;
  HFONT hOldFont = (HFONT)pDC->SelectObject ((HFONT)::GetStockObject (DEFAULT_GUI_FONT));
  UINT  state =lpDIS->itemState;
  if(state & ODS_FOCUS)
  {
    rtControl.DeflateRect(1,1);  //擁有焦點矩形變小
  }
  if((state & ODS_DISABLED) ||
    (!MouseOver() &&!(state & ODS_SELECTED)))
  {
    //普通狀態、禁用、擁有焦點三種情況下
    pen.CreatePen (PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
    brush.CreateSolidBrush(HLS_TRANSFORM(::GetSysColor(COLOR_3DFACE),-10,0));
  }
  else
  {
    COLORREF  crBorder =::GetSysColor(COLOR_HIGHLIGHT);
    pen.CreatePen(PS_SOLID, 1, crBorder);
    if( state & ODS_SELECTED)
    {
      //按鈕按下時
      brush.CreateSolidBrush(HLS_TRANSFORM(crBorder,+50,-50));
      pDC->SetTextColor(RGB(240,240,240));
    }
    else
    {
      //鼠標在區域內  
      brush.CreateSolidBrush(HLS_TRANSFORM(crBorder,+80,-66));
      pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT));
    }
  }
  if(state &ODS_DISABLED)
    pDC->SetTextColor(::GetSysColor(COLOR_GRAYTEXT));//灰色字:禁用狀態
  else if(state & ODS_SELECTED)
    pDC->SetTextColor(RGB(240,240,240));  //白色字:PUSH狀態
  else if(MouseOver())  
    pDC->SetTextColor(0);  //黑色字:熱感應狀態
  else
    pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT));  //黑色字:普通狀態  
  old_brush=pDC->SelectObject(&brush);
  old_pen =pDC->SelectObject(&pen);
  pDC->Rectangle(rtControl);
  pDC->SetBkMode(TRANSPARENT);
  GetWindowText(strText);
  pDC->DrawText(strText,rtControl,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
  if(state & ODS_FOCUS)
  {
    rtControl.DeflateRect(3,3);
    pDC->DrawFocusRect(rtControl);
  }
  pDC->SelectObject(old_pen);
  pDC->SelectObject(old_brush);
  pDC->SelectObject(hOldFont);
}

還有一個要注意的是,要使用TrackMouseEvent(),必須在加入頭文件winuser.h 和extern "C" WINUSERAPI BOOL WINAPI TrackMouseEvent(LPTRACKMOUSEEVENT lpEventTrack);

本程序在win98 + Visual C++ 6.0環境下編譯通過.

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