要想修改CButton類按鈕背景顔色和文字顔色,必須利用自繪方法對按鈕進行重新繪制。這可以通過定義一個以CButton為基類的新按鈕類來實作。以下為具體的實作方法:
方法一:
加入一個新類,類名:CButtonEx,基類:CButton。
在頭檔案 CButtonEx.h 中加入以下變量和函數定義:
private: int m_Style; //按鈕形狀(0-正常,1-目前,2-按下,3-鎖定) BOOL b_InRect; //滑鼠進入标志 CString m_strText; //按鈕文字 COLORREF m_ForeColor; //文本顔色 COLORREF m_BackColor; //背景色 COLORREF m_LockForeColor; //鎖定按鈕的文字顔色 CRect m_ButRect; //按鈕尺寸 CFont* p_Font; //字型
void DrawButton(CDC*pDC); //畫正常的按鈕
// 接口函數 public: void SetText(CString str); void SetForeColor(COLORREFcolor); //設定文本顔色 void SetBkColor(COLORREFcolor); //設定背景顔色 void SetTextFont(int FontHight,LPCTSTRFontName); //設定字型
在 CButtonEx.cpp 的構造函數中初始化變量:
CButtonEx::CButtonEx() { m_Style =0; //按鈕形狀風格 b_InRect =false; //滑鼠進入标志 m_strText =_T(""); //按鈕文字(使用預設文字) m_ForeColor = RGB(0,0,0); //文字顔色(黑色) m_BackColor =RGB(243,243,243); //背景色(灰白色) m_LockForeColor =GetSysColor(COLOR_GRAYTEXT); //鎖定按鈕的文字顔色 p_Font =NULL; //字型指針 }
用ClassWizard添加下列消息函數:
PreSubclassWindow(); DrawItem(); onMouseMove(); OnLButtonDown(); OnLButtonUp();
在各函數内加入代碼:
void CButtonEx::PreSubclassWindow() { ModifyStyle( 0, BS_OWNERDRAW); //設定按鈕屬性為自畫式 CButton::PreSubclassWindow(); }
PreSubclassWindow()在按鈕建立前自動執行,是以我們可以在其中做一些初始工作。這裡我隻做了一項工作,就是為按鈕設定屬性為“自繪”式,這樣,使用者在添加按鈕後,就不需設定“Owner draw”屬性了。
void CButtonEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { CDC *pDC = CDC::FromHandle( lpDrawItemStruct->hDC); m_ButRect =lpDrawItemStruct->rcItem; //擷取按鈕尺寸
if( m_strText.IsEmpty() ) GetWindowText( m_strText); //擷取按鈕文本
int nSavedDC = pDC->SaveDC(); VERIFY( pDC ); DrawButton( pDC); //繪制按鈕 pDC->RestoreDC( nSavedDC ); }
DrawItem()函數是一個關鍵函數,按鈕的繪制工作就在這裡進行,它的作用相當于對話框中的OnPaint()函數和視圖中的OnDraw()函數。
這裡我做了三項工作:擷取按鈕尺寸、擷取按鈕文本、繪制按鈕。其中繪制工作在自定義函數DrawButton()中完成。以下就是繪制過程:
void CButtonEx::DrawButton(CDC *pDC) { //調整狀态 if( m_Style==3 ) m_Style = 0; if( GetStyle() & WS_DISABLED ) m_Style =3; //禁止狀态 //根據狀态調整邊框顔色和文字顔色 COLORREF bColor, fColor; //bColor為邊框顔色,fColor為文字顔色 switch( m_Style ) { case 0: bColor = RGB(192,192,192); fColor =m_ForeColor; break; //正常按鈕 case 1: bColor = RGB(255,255,255); fColor =m_ForeColor; break; //滑鼠進入時按鈕 case 2: bColor = RGB(192,192,192); fColor =m_ForeColor; break; //按下的按鈕 case 3: bColor = m_BackColor; fColor =m_LockForeColor; break; //鎖定的按鈕 } //繪制按鈕背景 CBrush Brush; Brush.CreateSolidBrush( m_BackColor); //背景刷 pDC->SelectObject( &Brush ); CPen Pen; Pen.CreatePen(PS_SOLID, 1, bColor ); pDC->SelectObject( &Pen ); pDC->RoundRect(&m_ButRect,CPoint(5,5)); //畫圓角矩形 //繪制按鈕按下時的邊框 if( m_Style!=2 ) { CRect Rect; Rect.SetRect(m_ButRect.left+2, m_ButRect.top+1, m_ButRect.right, m_ButRect.bottom ); pDC->DrawEdge( &Rect,BDR_RAISEDINNER, BF_RECT ); //畫邊框 } //繪制按鈕文字 pDC->SetTextColor( fColor); //畫文字 pDC->SetBkMode( TRANSPARENT ); pDC->DrawText( m_strText, &m_ButRect,DT_SINGLELINE | DT_CENTER | DT_VCENTER |DT_END_ELLIPSIS); //繪制擁有焦點按鈕的虛線框 if( GetFocus()==this ) { CRect Rect; Rect.SetRect(m_ButRect.left+3, m_ButRect.top+2, m_ButRect.right-3, m_ButRect.bottom-2 ); pDC->DrawFocusRect(&Rect ); //畫擁有焦點的虛線框 } }
變量 m_Style 表征目前按鈕狀态,它的取值為:0-正常,1-目前,2-按下,3-鎖定。不同狀态下按鈕的邊框顔色和文字顔色有所不同。m_Style 的值在滑鼠響應函數中進行修改。
繪制工作主要利用CDC類的繪圖函數完成,主要注意在 m_Style 不同取值下表現出來的差别。
void CButtonEx::onMouseMove(UINT nFlags, CPoint point) { if( !b_InRect || GetCapture()!=this) //滑鼠進入按鈕 { b_InRect =true; //設定進入标志 SetCapture(); //捕獲滑鼠 m_Style =1; //設定按鈕狀态 Invalidate(); //重繪按鈕 } else { if (!m_ButRect.PtInRect(point) ) //滑鼠離開按鈕 { b_InRect = false; //清除進入标志 ReleaseCapture(); //釋放捕獲的滑鼠 m_Style = 0; //設定按鈕狀态 Invalidate(); //重繪按鈕 } } CButton::onMouseMove(nFlags, point); }
onMouseMove()函數是滑鼠移動消息函數,用于判定目前滑鼠指針是否在按鈕上。b_InRect是個标志,為true表示滑鼠指針進入了按鈕區域,此時要捕獲滑鼠,讓滑鼠指令傳送給按鈕。當滑鼠指針離開按鈕時,要清除b_InRect标志,并且釋放捕獲的滑鼠,讓其它視窗可以接收滑鼠指令。
Invalidate()函數用于更新按鈕,它會自動調用DrawItem()函數重新繪制按鈕。
設定條件的目的是僅在滑鼠指針進入按鈕和離開按鈕時更新按鈕,這樣可以防止滑鼠在按鈕上移動時發生閃爍。
void CButtonEx::OnLButtonDown(UINT nFlags, CPoint point) { m_Style = 2; Invalidate(); //重繪按鈕 CButton::OnLButtonDown(nFlags, point); }
OnLButtonDown()函數是單擊滑鼠左鍵時的消息函數。這裡隻是重新繪制按鈕,具體的單擊響應應該在擁有按鈕的對話框或視圖中進行。
void CButtonEx::OnLButtonUp(UINT nFlags, CPoint point) { m_Style = 1; Invalidate(); //重繪按鈕 CButton::OnLButtonUp(nFlags, point); }
OnLButtonUp()函數是單擊滑鼠左鍵後彈起時的消息函數。這裡也隻是重繪按鈕,這樣能使按鈕在按下和彈起時有所不同,使按鈕看上去有動态效果。
接口函數是用 CButtonEx類 定義的按鈕修改顔色、字型和按鈕文字的接口,由以下函數組成:
//設定按鈕文本 void CButtonEx::SetText(CString str) { m_strText = _T(""); SetWindowText(str); }
//設定文本顔色 void CButtonEx::SetForeColor(COLORREF color) { m_ForeColor = color; Invalidate(); }
//設定背景顔色 void CButtonEx::SetBkColor(COLORREF color) { m_BackColor = color; Invalidate(); }
//設定字型(字型高度、字型名) void CButtonEx::SetTextFont(int FontHight,LPCTSTR FontName) { if ( p_Font )
deletep_Font; //删除舊字型 p_Font = new CFont; p_Font->CreatePointFont( FontHight, FontName); //建立新字型 SetFont( p_Font); //設定字型 }
由于新字型由 new 生成,必須顯式回收,這項工作可以在 CButtonEx類 的析構函數中進行:
CButtonEx::~CButtonEx() { if ( p_Font )
deletep_Font; //删除字型 }
這樣一個可設定顔色、字型的按鈕類就做好了。使用時,先在對話框中放置好按鈕,再用 ClassWizard 為按鈕添加控制變量,并且将變量的類型設定為 CButtonEx。之後,可以用該變量調用接口函數設定按鈕顔色和字型。
以上測試過,太複雜。又生一類。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
方法二:
添加dlg類的WM_DRAWITEM消息處理函數
void CBtncolorDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCTlpDrawItemStruct) { // TODO: Add your message handler code here and/or call default if(nIDCtl==IDC_BUTTON1) //checking for the button { CDC dc; RECT rect; dc.Attach(lpDrawItemStruct ->hDC); // Get theButton DC to CDC rect = lpDrawItemStruct->rcItem; //Store the Button rect to our local rect. dc.Draw3dRect(&rect,RGB(255,255,255),RGB(0,0,0));
dc.FillSolidRect(&rect,RGB(100,100,255));//Here youcan define the required color to appear on the Button.
UINT state=lpDrawItemStruct->itemState; //Thisdefines the state of the Push button either pressed or not.
if((state & ODS_SELECTED)) { dc.DrawEdge(&rect,EDGE_SUNKEN,BF_RECT);
} else { dc.DrawEdge(&rect,EDGE_RAISED,BF_RECT); }
dc.SetBkColor(RGB(100,100,255)); //Settingthe Text Background color dc.SetTextColor(RGB(255,0,0)); //Setting the Text Color
TCHARbuffer[MAX_PATH]; //To store the Caption of the button. ZeroMemory(buffer,MAX_PATH ); //Intializing the buffer to zero ::GetWindowText(lpDrawItemStruct->hwndItem,buffer,MAX_PATH); //Get theCaption of Button Window dc.DrawText(buffer,&rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE);//Redrawthe Caption of Button Window dc.Detach(); // Detach the Button DC } CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);
}