zoukankan      html  css  js  c++  java
  • 【C++】DDX_Control、SubclassWindow和SubclassDlgItem的区别

    在自绘窗口的时候,子类化是MFC最常用的窗体技术之一。什么是子类化?窗口子类化就是创建一个新的窗口函数代替原来的窗口函数。

    Subclass(子类化)是MFC中最常用的窗体技术之一。子类化完成两个工作:一是把窗体类对象attach到一个windows窗体实体中(即把一个窗体的hwnd赋给该类)。另外就是把该类对象的消息加入到消息路由中,使得该类可以捕获消息。

    而通常我们会碰到DDX_Control、SubclassWindow、SubclassDlgItem等,不同的子类化方法。首先先看下面的代码:

    void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl)
    {
    if ((rControl.m_hWnd == NULL) && (rControl.GetControlUnknown() == NULL))    // not subclassed yet
    {
    ASSERT(!pDX->m_bSaveAndValidate);
    
    pDX->PrepareCtrl(nIDC);
      HWND hWndCtrl;
      pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
    if ((hWndCtrl != NULL) && !rControl.SubclassWindow(hWndCtrl))
    {
    ASSERT(FALSE);      // possibly trying to subclass twice?
    AfxThrowNotSupportedException();
    }
    #ifndef _AFX_NO_OCC_SUPPORT
    else
    {
     if (hWndCtrl == NULL)
     {
    if (pDX->m_pDlgWnd->GetOleControlSite(nIDC) != NULL)
    {
       rControl.AttachControlSite(pDX->m_pDlgWnd, nIDC);
    }
     }
     else
     {
       // If the control has reparented itself (e.g., invisible control),
       // make sure that the CWnd gets properly wired to its control site.
       if (pDX->m_pDlgWnd->m_hWnd != ::GetParent(rControl.m_hWnd))
       rControl.AttachControlSite(pDX->m_pDlgWnd);
     }
    }
    #endif //!_AFX_NO_OCC_SUPPORT
    
    }
    }

    我们发现 DDX_Control()函数中调用了SubclassWindow(),再看SubclassWindow()里写了什么:

    // From VS Install PathVC98MFCSRCWINCORE.CPP  
    BOOL CWnd::SubclassWindow(HWND hWnd)  
    {  
        if (!Attach(hWnd))  
            return FALSE;  
          
        // allow any other subclassing to occur  
        PreSubclassWindow();  
          
        // now hook into the AFX WndProc  
        WNDPROC* lplpfn = GetSuperWndProcAddr();  
        WNDPROC oldWndProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC,  
            (DWORD)AfxGetAfxWndProc());  
        ASSERT(oldWndProc != (WNDPROC)AfxGetAfxWndProc());  
          
        if (*lplpfn == NULL)  
            *lplpfn = oldWndProc;   // the first control of that type created  
    #ifdef _DEBUG  
        else if (*lplpfn != oldWndProc)  
            {  
              
                ::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)oldWndProc);  
        }  
    #endif  
          
        return TRUE;  
    }  
      
    很显然,SubclassWindow()中调用了Attach()函数和reSubclassWindow()函数,由于SubclassWindow()函数是不可重载的,而PreSubclassWindow()函数是可重载的,所以我们经常重载PreSubclassWindow()函数,以致于 窗口被子类化之前进行其它的必要的子类化,看下它原来的声明:
    CWnd::PreSubclassWindow
    virtual void PreSubclassWindow( );

    而SubclassWindow又与SubclassDlgItem有什么区别?前者用于一切具有HWND的窗体,后者只限定于对话框控件

    用法:在OnInitDialog中调用SubclassDlgItem将派生类的控件对象与对话框中的基类控件相连接,则这个基类控件对象变成了派生控件对象


    总而言之,比较常用的就是DDX_Control。


  • 相关阅读:
    微信红包高并发交易
    MQ夺命11问
    美团雪花LEAF算法
    Mysql一遍过
    分布式
    如何注册和发现服务
    服务发布和引用
    微服务的构成
    什么是微服务
    Java的动态代理
  • 原文地址:https://www.cnblogs.com/riskyer/p/3424278.html
Copyright © 2011-2022 走看看