MFC自定义按钮的实现
来源:互联网 发布:微软access数据库 编辑:程序博客网 时间:2024/06/05 02:10
学习MFC的都知道,我们要想改变对话框和控件的背景以及文本颜色,可以响应OnCtlColor消息,在这个函数里面进行相应的设置,如下所示:
HBRUSH StatusBar::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor){ HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor); // TODO: Change any attributes of the DC here // TODO: Return a different brush if the default is not desired switch (nCtlColor) { case CTLCOLOR_BTN: case CTLCOLOR_STATIC: pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(RGB(200, 255, 255)); case CTLCOLOR_DLG: return (HBRUSH)m_brBack.GetSafeHandle(); } return hbr;}
但是对于按钮来说上述方法是不起作用的,只能寻找其他解决办法。实际上,要想改变按钮的背景色和文本颜色,需要使用CButton类的一个成员函数DrawItem,该函数的声明如下:// Overridables (for owner draw only)
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
这个函数是一个虚函数,当一个自绘制按钮在绘制时候,框架将会调用这个虚函数。因此,如果想要实现一个自绘按钮,就应该重载这个虚函数。该函数的参数是DRAWITEMSTRUCT结构类型,定义如下:
typedef struct tagDRAWITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; ULONG_PTR itemData;} DRAWITEMSTRUCT;
该结构体有一个hDC成员,指向将要绘制的按钮的DC。为了绘制这个按钮,可以向该DC中选入自定义的颜色、画刷等对象。了解了这些知识,下面开始真正的自绘按钮,首先看一下效果,效果如下:
这里列出了按钮的几种状态,第一种是正常状态,第二种是按下之后的状态,第三中是不同的背景颜色,这里设置了两种不同的背景颜色,实际上这里的背景是图片,所以看起来会有立体的感觉!
以下是.h文件源代码,看起来应该不难^_^:
class CPicButton : public CButton{public: CPicButton(void); ~CPicButton(void);public: enum { MAX_BTN_COLOR = 3 }; enum { COLOR_NORMAL = 0, COLOR_FOCUSED = 1, COLOR_PRESSED = 2 }; //按钮的三种状态 COLORREF m_crForeColor[MAX_BTN_COLOR]; UINT m_nTypeStyle; int m_nColorType; BOOL m_bMouseOnButton; // Is mouse over the button? BOOL m_bIsPressed; // Is button pressed? BOOL m_bIsFocused; // Is button focused? BOOL m_bIsDisabled; // Is button disabled? CString m_sFontName; //字体名字 int m_nFontWidth, m_nFontHeight; //字体大小 BOOL m_bPointFont;public: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); //这里是重点,通过调用Invalidate()可以马上重绘按钮,从而调用这个函数 virtual BOOL PreTranslateMessage(MSG *pMsg); void SetForeColor(int nIndex, COLORREF color, BOOL bRepaint = TRUE);//设置前景色 void SetColorType(int nColorIdx); //设置背景颜色的类别,在这里代表两种背景图片 void SetCaptionFont(CString sFontName, int nWidth, int nHeight, BOOL bPointFont=FALSE);protected: virtual void PreSubclassWindow();//在这里面修改按钮的样式 virtual void DrawBackground(CDC *dc, int nWidth, int nHeight);//绘制背景 virtual void DrawBtnCaption(CDC *dc, int nWidth, int nHeight);//绘制字体private: void FreeResources(); void CancelHover();public: afx_msg BOOL OnClicked();//点击事件 afx_msg void OnKillFocus(CWnd* pNewWnd); afx_msg void OnMouseMove(UINT nFlags, CPoint point);//鼠标移动事件 afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);DECLARE_MESSAGE_MAP()};
#include "stdafx.h"#include "PicBtn.h"#include "DrawingTools.h"#include "Resource.h"CPicButton::CPicButton(void){ m_crForeColor[COLOR_NORMAL] = RGB(0, 0, 0); m_crForeColor[COLOR_FOCUSED] = RGB(240, 240, 240); m_crForeColor[COLOR_PRESSED] = RGB(255, 255, 255); m_nColorType = 0; // Brown or Red m_bMouseOnButton = FALSE; m_bIsPressed = FALSE; m_bIsFocused = FALSE; m_bIsDisabled = FALSE; m_nFontHeight = 17; m_nFontWidth = 6; m_bPointFont = FALSE; m_sFontName = _T("Arial");}CPicButton::~CPicButton(void){ FreeResources();}void CPicButton::FreeResources(){}void CPicButton::CancelHover(){ if (m_bMouseOnButton) { m_bMouseOnButton = FALSE; Invalidate(); }} void CPicButton::PreSubclassWindow(){#if defined(_CE_VERSION) ModifyStyle(0, BS_OWNERDRAW, SWP_FRAMECHANGED);#else UINT nBS = GetButtonStyle(); m_nTypeStyle = nBS & BS_TYPEMASK; if (m_nTypeStyle == BS_DEFPUSHBUTTON) { m_nTypeStyle = BS_PUSHBUTTON; }// You should not set the Owner Draw before this call // (don't use the resource editor "Owner Draw" or // ModifyStyle(0, BS_OWNERDRAW) before calling PreSubclassWindow()) ASSERT(m_nTypeStyle != BS_OWNERDRAW);//Switch to owner-draw ModifyStyle(BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);#endif CButton::PreSubclassWindow();}BOOL CPicButton::PreTranslateMessage(MSG* pMsg){ if (pMsg->message == WM_LBUTTONDBLCLK) pMsg->message = WM_LBUTTONDOWN; return CButton::PreTranslateMessage(pMsg);}void CPicButton::SetColorType(int nColorIdx){ m_nColorType = nColorIdx;}void CPicButton::SetCaptionFont(CString sFontName, int nWidth, int nHeight, BOOL bPointFont){ m_sFontName = sFontName; m_nFontWidth = nWidth; m_nFontHeight = nHeight; m_bPointFont = bPointFont; Invalidate();}BEGIN_MESSAGE_MAP(CPicButton, CButton) ON_WM_KILLFOCUS() ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked) //消息反射 ON_WM_ACTIVATE()#ifndef _CE_VERSION ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)#endifEND_MESSAGE_MAP()#ifndef _CE_VERSIONvoid CPicButton::OnMouseMove(UINT nFlags, CPoint point){ CWnd *wndUnderMouse = NULL; CWnd *wndActive = this; TRACKMOUSEEVENT csTME; CButton::OnMouseMove(nFlags, point); ClientToScreen(&point); wndUnderMouse = WindowFromPoint(point);//获得点下面的组件 // If the mouse enter the button with the left button pressed then do nothing if (nFlags & MK_LBUTTON && m_bMouseOnButton == FALSE) return; if (wndUnderMouse && wndUnderMouse->m_hWnd == m_hWnd && wndActive) { if (!m_bMouseOnButton) { m_bMouseOnButton = TRUE; Invalidate(); csTME.cbSize = sizeof(csTME); csTME.dwFlags = TME_LEAVE; csTME.hwndTrack = m_hWnd; ::_TrackMouseEvent(&csTME);//发送鼠标离开的消息,见我之前的博客 } } else CancelHover();}LRESULT CPicButton::OnMouseLeave(WPARAM wParam, LPARAM lParam){ CancelHover(); return 0;}#endifBOOL CPicButton::OnClicked(){ SetFocus();//设置焦点 Invalidate(); return FALSE;}void CPicButton::DrawItem(LPDRAWITEMSTRUCT lpDIS){ CDC *pDC = CDC::FromHandle(lpDIS->hDC); //获取CDC int nWidth, nHeight; CRect itemRect = lpDIS->rcItem; nWidth = itemRect.Width(); nHeight = itemRect.Height(); m_bIsPressed = (lpDIS->itemState & ODS_SELECTED);//是不是已经按下 m_bIsFocused = (lpDIS->itemState & ODS_FOCUS); //是不是获得了焦点 m_bIsDisabled = (lpDIS->itemState & ODS_DISABLED); //是不是没使能 pDC->SetBkMode(TRANSPARENT);//设置背景透明 DrawBackground(pDC, nWidth, nHeight);//画背景 DrawBtnCaption(pDC, nWidth, nHeight); //画字体}void CPicButton::DrawBackground(CDC *dc, int nWidth, int nHeight){ if (m_bIsPressed) { if (m_nColorType == 0) ::DrawBMP(dc,IDB_BTN_YP, 0, 0); // else ::DrawBMP(dc,IDB_BTN_RP, 0, 0);//画红色按下背景 } else { if (m_nColorType == 0) ::DrawBMP(dc,IDB_BTN_Y, 0, 0); else ::DrawBMP(dc,IDB_BTN_R, 0, 0);//画红色背景 }}void CPicButton::DrawBtnCaption(CDC *dc, int nWidth, int nHeight){ CString str; CRect rect; int nColorIndex; CFont font, *old_font; if (m_bIsPressed) nColorIndex = COLOR_PRESSED; else if (m_bMouseOnButton) nColorIndex = COLOR_FOCUSED; else nColorIndex = COLOR_NORMAL; if (m_bPointFont) font.CreatePointFont(m_nFontHeight * 10, m_sFontName); else { font.CreateFont(m_nFontHeight, m_nFontWidth, 0, 0, FW_BOLD, 0, 0, 0, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, m_sFontName); } GetWindowText(str); rect = CRect(2, 2, nWidth - 4, nHeight - 4); old_font = dc->SelectObject(&font); dc->SetTextColor(m_crForeColor[nColorIndex]); //显示字体 dc->DrawText(str, str.GetLength(), &rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER); dc->SelectObject(old_font); font.DeleteObject();}void CPicButton::SetForeColor(int nIndex, COLORREF crColor, BOOL bRepaint){ m_crForeColor[nIndex] = crColor; if (bRepaint) Invalidate();}void CPicButton::OnKillFocus(CWnd * pNewWnd){ CButton::OnKillFocus(pNewWnd); CancelHover();//当失去焦点的时候,需要改变字体颜色,需要重绘,调用Invalidate();}void CPicButton::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized){ CButton::OnActivate(nState, pWndOther, bMinimized); if (nState == WA_INACTIVE) //当失去焦点的时候,需要改变字体颜色,需要重绘,调用Invalidate(); CancelHover();}
自定义按钮类已经写好了,那么怎么和对话框中的按钮关联起来呢?方法如下:
在.h中:#include "PicBtn.h"CPicButton m_btnExit;在.cpp中:void CFiveChessDlg::DoDataExchange(CDataExchange* pDX){ CDialogEx::DoDataExchange(pDX); //这里就把我们对话框中的按钮和我们自定义的按钮类关联起来了 DDX_Control(pDX, IDC_BUTTON_Quit, m_btnExit);}//设置按钮的显示字体,背景颜色等等,这个函数可以放在OnInitDialog函数里面调用void CFiveChessDlg::InitButton(){ m_btnExit.SetCaptionFont(_T("SimHei"), 0, 12, TRUE); m_btnExit.SetWindowText(_T("退出")); m_btnExit.SetColorType(1);}
然后就和正常的按钮一样响应点击事件就可以了!
通过以上自定义按钮的方法进行扩展,可以做出我们需要的效果,比如在按钮上显示图片和文字或者就纯粹的图片按钮等等,QQ界面就用了很多的图片按钮!
下面是我自定义的另外一种按钮:这个就比较简单了,代码和之前的那个图片背景的差不多,只是它这个背景有三种颜色,而之前的是字体有三种颜色而已!
顺便讲一下上面这个对话框顶部尖尖的地方以及按钮等间隔和等大小是怎么实现的,代码如下:
//按钮等间隔和等大小的实现void CSetting_Menu::UpdateLayout(){ CRect rect1,rect2; rect1.top = 0; rect1.left = 0; rect1.right = rect1.left + 250; rect1.bottom = rect1.top + 315; MoveWindow(rect1);//设置对话框的大小,固定的 if (GetDlgItem(IDC_BUTTON_General_Setting)) { rect1.left = 5; rect1.right = rect1.left+240; rect1.top = 15; rect1.bottom = rect1.top + 45; GetDlgItem(IDC_BUTTON_General_Setting)->MoveWindow(rect1); //移动按钮到这个位置 } if (GetDlgItem(IDC_BUTTON_COM_Port_Setting)) { rect1.left = 5; rect1.right = rect1.left + 240; rect1.top = 5*4+45; rect1.bottom = rect1.top + 45; GetDlgItem(IDC_BUTTON_COM_Port_Setting)->MoveWindow(rect1); } if (GetDlgItem(IDC_BUTTON_DataFile_Setting)) { rect1.left = 5; rect1.right = rect1.left + 240; rect1.top = 5*5 + 45*2; rect1.bottom = rect1.top + 45; GetDlgItem(IDC_BUTTON_DataFile_Setting)->MoveWindow(rect1); } if (GetDlgItem(IDC_BUTTON_General_Command)) { rect1.left = 5; rect1.right = rect1.left + 240; rect1.top = 5*6 + 45*3; rect1.bottom = rect1.top + 45; GetDlgItem(IDC_BUTTON_General_Command)->MoveWindow(rect1); } if (GetDlgItem(IDC_BUTTON_AutoClib_Setting)) { rect1.left = 5; rect1.right = rect1.left + 240; rect1.top = 5*7 + 45*4; rect1.bottom = rect1.top + 45; GetDlgItem(IDC_BUTTON_AutoClib_Setting)->MoveWindow(rect1); } if (GetDlgItem(IDC_BUTTON_ACC_GYRO_Scale)) { rect1.left = 5; rect1.right = rect1.left + 240; rect1.top = 5*8 + 45*5; rect1.bottom = rect1.top + 45; GetDlgItem(IDC_BUTTON_ACC_GYRO_Scale)->MoveWindow(rect1); }}
以上代码就是对对话框的进行了一个布局,这样就看起来比较规整,按钮的大小和间隔都是一样的!//对话框顶部凸起部分的实现CPoint pts[7] = { CPoint(0, 10), CPoint(40, 10), CPoint(50, 0), CPoint(60, 10), CPoint(250, 10), CPoint(250, 315), CPoint(0, 315)};//创建一个多边形区域,以上面定义的七个顶点为边界 HRGN poloy = CreatePolygonRgn(pts, 7, ALTERNATE); CRgn rgn; rgn.Attach(poloy); SetWindowRgn(rgn,TRUE); //设置窗口的多边形形状 rgn.Detach();以上代码就可以把对话框设置成各种形状了,是不是很Cool ^_^。
- MFC自定义按钮的实现
- MFC自定义按钮实现CRgnButton
- MFC内单选按钮的实现
- 自定义形状按钮的实现
- MFC自绘按钮的实现
- MFC下按钮自绘的实现
- MFC 自绘按钮的实现
- 【MFC】按钮提示功能的实现
- PNG透明背景按钮的实现(MFC)
- MFC中位图按钮的实现方法:
- MFC自绘按钮的实现
- MFC 自绘按钮的实现
- MFC下按钮自绘的实现
- MFC图形按钮/自定义颜色
- MFC中自定义按钮响应键盘的回车操作
- 在Android中实现自定义的按钮
- Windows Phone 7 自定义按钮的实现
- 安卓自定义按钮的实现
- [华为机试练习题]9.坐标移动
- 严重: Unable to set localhost. This prevents creation of a GUID. Cause was: cloud: cloud
- Myeclipse安装配置优化
- CMake 编译OSG 3.2.1 使用QT 5.4
- android处理home键的方法
- MFC自定义按钮的实现
- WebView加载本地加载网络资源
- struts2上传工具类
- LeetCode Add Two Numbers
- android 样式的使用
- 《Java程序设计》第三次作业:网络编程~
- Macaulay2 on Windows
- 画1像素的线
- Python 深入理解yield