CMFCButton类介绍

CMFCButton类介绍
此类是基于MFC基本 CButton类型集成而来的,具备CButton拥有的基本按钮属性和操作方法,此外它还具有一些特殊的功能:
----------------------------------------------------------------------------------------
更改文字:   button-> SetWindowTextW(_T("强制更改")); 
更改背景颜色:  button-> SetFaceColor(RGB(153, 217, 234));  
更改字体颜色:   button-> SetTextColor(RGB(255, 255, 255));  
更改高亮颜色:   button-> SetTextHotColor(RGB(63, 72, 204));  
更改位置:   button-> MoveWindow(50, 50, 100, 70); 
鼠标经过时变成手势:   button-> SetMouseCursorHand();
工具提示: button-> SetTooltip(_T("俺是提示"));
加载图片: button-> SetImage(IDB_BITMAP1); 
----------------------------------------------------------------------------------------
其中button为CMFCButton指针: CMFCButton  * button
由于CMFCButton是由MFC自己提供的,所以只要在源文件中加入“ include <afxbutton.h>”即可直接使用。此外基于CMFCButton的派生类也有很多:
BUTTON - CMFCButton - dingmz_frc - dingmz_frc的博客
每个派生类都有某一方面的功能。

CMFCButton类使用方法
1、使用在对话框上直接拖放一个标准按钮控件,为此按钮添加变量,然后用CMFCButton直接替换CButton即可。如在对话框        上放置了两个按钮 BUTTON1BUTTON2.
2、在OnInitDlg或OnPaint等函数处对按钮进行修改,如在 OnInitDlg中添加以下语句

// 更改文字  

button1->SetWindowTextW(_T("强制更改"));  

// 更改背景颜色  

button1->SetFaceColor(RGB(153, 217, 234));  

// 更改字体颜色  

button1->SetTextColor(RGB(255, 255, 255));  

// 更改高亮颜色  

button1->SetTextHotColor(RGB(63, 72, 204));  

// 更改位置  

button1->MoveWindow(50, 50, 100, 70);  

// 鼠标经过时变成手势  

button1->SetMouseCursorHand();  

// 工具提示  

button1->SetTooltip(_T("俺是提示"));

CMFCButton * button2 = new CMFCButton;  

button2->Create(_T("Test Button"), WS_VISIBLE, CRect(160, 15, 280, 150), this, IDC_BUTTON2);  

// 加载图片  

button2->SetImage(IDB_BITMAP1);

则显示效果如下所示:
BUTTON - CMFCButton - dingmz_frc - dingmz_frc的博客

使用起来比较简单,但是还是有缺陷,请看下节内容。

CMFCButton使用过程中发生内存泄露  - 此处引用他人地方,本人使用也遇到了此问题
问题发现过程
--------------------------------------------------------------------------------------------------------
打开vs2010,新建一个对话框工程,什么都不做,运行,推出的时候看不到内存泄露,但是当你拖一个mfc button到对话框上时,运行程序,推出的时候会看到发生了内存泄露。现在还不知道什么原因。
--------------------------------------------------------------------------------------------------------
具体的原因分析
--------------------------------------------------------------------------------------------------------
首先我们应该从VS2010提供的一些新类,比如 CMFCButton的创建过程着手分析。

在CDialog:: OnInitDialog()的执行过程中,会调用CMFCControlContainer:: SubclassDlgControls()函数对对话框内的各种控件进行初始化,由于VS2010引入了一些新的控件类,这些控件类在本质上又不是新创造出来的类,而是原来的一些类的子类,比如 CMFCButton就是CButton的一个子类,这样在一个CMFCButton创建的时候就需要进行一次 重子类化的过程。
--------------------------------------------------------------------------------------------------------
详细的跟踪过程如下
--------------------------------------------------------------------------------------------------------
1、  CDialog::OnInitDialog()函数会创建对话框界面上的控件,然后把这些对象保存起来。这个时候如果对话框模板被定义了会执    

        行ExecuteDlgInit()函数。

2、  ExecuteDlgInit()函数会调用CMFCControlContainer::SubclassDlgControls()开始子类化对话框内的控件。

3、  接下来CMFCControlContainer::CreateDlgControl()函数被调用,会创建一个CMFCBUTTON对象。

4、  然后会将该CMFCBUTTON对象进行子类化SubclassWindow()。

5、  然后会进入CMFCBUTTON对象的PreSubclassWindow()函数,这个函数基本上没有做什么事情。

6、  然后函数返回到ExecuteDlgInit()函数,这个时候对话框会发送一个WM_MFC_INITCTRL消息给该CMFCBUTTON对象。也就

        是在这个时候CMFCBUTTON对象的消息提示控件m_pToolTip第一次被创建。

        而这个创建的过程是委托给一个CTooltipManager类来管理的,这个类会将当前创建消息提示控件m_pToolTip的窗口(也就  

        是m_pToolTip的父窗口)的句柄记录下来。

7、  然后到了CWnd::UpdateData()函数,他用于更新和控件绑定的数据,接下来到了DoDataExchange(CDataExchange* pDX)

       函数,然后是DDX_Control(pDX, IDC_MFCBUTTON1, mfcbut)函数,在这个函数中会 重新子类化控件,即

  CMFCControlContainer *  pMFCCtrlContainer  =  pDX -> m_pDlgWnd -> GetMFCControlContainer ();
   if   ( pMFCCtrlContainer  !=  NULL  &&  pMFCCtrlContainer -> IsSubclassedFeaturePackControl ( hWndCtrl ))
   {
    pMFCCtrlContainer -> ReSubclassControl ( hWndCtrl ,   ( WORD ) nIDC ,  rControl );
    return ;
   }


8、   然后消息又走到了CMFCButton对象的PreSubclassWindow()函数。

9、  子类化成功后CMFCControlContainer类又会发送一个WM_MFC_INITCTRL消息。又对m_pToolTip进行了初始化。

       然而在该 CMFCButton对象 被销毁的时候,OnDestroy()中,会把最后一次创建的m_pToolTip对象删除。这貌似不合逻辑,似乎 少删除了一个m_pToolTip对象
--------------------------------------------------------------------------------------------------------
果然是这么回事
我想了很久才发现, 第一次子类化的时候用到的 CMFCButton对象是我们 不绑定任何数据的对象,而第二次用到的才是我们定义的CMFCButton对象。那么按照顺序就是“ 开始的控件”- 子类化-“ 第一个控件”-- 子类化--“ 第二个控件”,实际上 第二次子类化的并不是最开始的那个对象。而实际上 “第一个控件”和“第二个控件”的句柄是相同,那么在 “delete”的时候只会销毁第二次生成的“m_pToolTip”,第一次的没有被销毁。这样就合理了。
--------------------------------------------------------------------------------------------------------
解决的办法有两种

1、动态创建CMFCButton对象

2、修改DoDataExchange函数,主要是 重载DDX_Control函数,在其中 销毁tooltip控件。当你确定在使用CMFCButton的时候,可以调用这个函数。即重载CMFCButton中的 DDX_Control函数:

void   MFC_DDX_Control ( CDataExchange *  pDX ,   int  nIDC ,   CWnd &  rControl )
{
    HWND hWndCtrl ;
    pDX -> m_pDlgWnd -> GetDlgItem ( nIDC ,   & hWndCtrl );    
    TCHAR lpszClassName  [ MAX_CLASS_NAME  +   1 ];
     :: GetClassName ( hWndCtrl ,  lpszClassName ,  MAX_CLASS_NAME );
     CString  strClass  =  lpszClassName ;
     if   ( strClass  ==  _T ( "MFCButton" ))
     {
         CMFCButton   * pMFCButton  =   ( CMFCButton   *) pDX -> m_pDlgWnd -> GetDlgItem ( nIDC );
         CToolTipCtrl &  pToolTipCtrl  =  pMFCButton -> GetToolTipCtrl ();
         if   ( pToolTipCtrl . m_hWnd  !=  NULL )
         {
             CToolTipCtrl *  pCtrl  =   & pToolTipCtrl ;
             CTooltipManager :: DeleteToolTip ( pCtrl );
         }
     }
    DDX_Control ( pDX ,  nIDC ,  rControl );
}
void   CShrinkWndDlg :: DoDataExchange ( CDataExchange *  pDX )
{
     CDialogEx :: DoDataExchange ( pDX );
    MFC_DDX_Control ( pDX ,  IDC_MFCBUTTON1 ,  mfcbut );
}
  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值