采用模板的手法复用CWnd类

 

      MFC框架由于古老,其与模板的结合比ATL/WTL差远了,其中一大原因就是因为宏的大量使用。最近封装MFC窗口类(CWnd),实在不想机械性地使用虚函数机制了,就想试试通过模板的手法实现代码的复用性。真的动起手来,其实发现也没那么麻烦。

     CWnd采用模板手法,最大的障碍就是宏的使用。由于CWnd中的宏都分为声明和定义2部分,声明在.h文件,定义在.cpp文件中。由于模板的具现化在编译器,最简单的解决就是将.cpp改成.inl格式,并在头文件末尾包含这个.inl文件。

类声明中的DECLARE_DYNAMICDECLARE_MESSAGE_MAP由于不需要模板参数可以暂且不管,类定义中对应的宏: IMPLEMENT_DYNAMICBEGIN_MESSAGE_MAP/ END_MESSAGE_MAP才是需要定制的关键。本想查看这些宏的定义以便自己实现对应的模板函数/变量,可当我看见BEGIN_TEMPLATE_MESSAGE_MAP宏时,才发现这个宏正是我想要的那种定制(可惜文档上查不到),省去一番功夫,以此类推, DECLARE_DYNAMIC宏肯定也有对应的模板形式,找了好久,勉勉强强找到了IMPLEMENT_DYNAMIC_T,但是这个宏虎头蛇尾的,根本就用不了。本想自己实现一个,可仔细想想这个宏的作用,才发现自己的模板类真的不需要。这个宏作用在乎给MFC类添加个静态变量,编制该类的类名,从而实在MFCRTTI机制。但我的模板类只是封装代码,使其可复用,RTTI机制的支持完全可以放到具体的实现类中。

    不知不觉中发现自己废话真有点多了,先上代码吧:

    .h文件:

      代码

template < typename T >
class  CAuxWindowT :  public  CWnd
{
    DECLARE_DYNAMIC(CAuxWindowT)
public :
    CAuxWindowT();   
//  标准构造函数
     virtual   ~ CAuxWindowT();

public :
    BOOL CreateWnd(DWORD dwExStyle, LPCTSTR lpszWindowName, DWORD dwStyle, 
const  RECT &  rect, CWnd *  pParentWnd, UINT nID, LPVOID lpParam  =  NULL);

protected :
    
virtual   void  DoDataExchange(CDataExchange *  pDX);     //  DDX/DDV 支持

    DECLARE_MESSAGE_MAP()
    
int   OnCreate(LPCREATESTRUCT lpCreateStruct);
    
void  OnPaint();
    BOOL OnEraseBkgnd(CDC
*  pDC);
};

#include 
" AuxWindow.inl "

 

 文件AuxWindow.inl的代码如下:

代码
#define  DECLARE_TEMPLATE_THIS_POINTER(type, var)      \
    type
*  var  =  static_cast < type *> ( this );    \
    ATLASSERT(var 
!=  NULL);

// IMPLEMENT_DYNAMIC_T(CAuxWindowT, T, CWnd)

template
< typename T >
CAuxWindowT
< T > ::CAuxWindowT()
{

}

template
< typename T >
CAuxWindowT
< T > :: ~ CAuxWindowT()
{
}

template
< typename T >
BOOL CAuxWindowT
< T > ::CreateWnd(DWORD dwExStyle, LPCTSTR lpszWindowName, DWORD dwStyle,  const  RECT &  rect, CWnd *  pParentWnd, UINT nID, LPVOID lpParam)
{
    DECLARE_TEMPLATE_THIS_POINTER(T, pThis);

    CAuxInitWinStruct
< WNDCLASSEX >   wndClass;
    wndClass.lpfnWndProc    
=  ::DefWindowProc;
    wndClass.hInstance        
=  AfxGetInstanceHandle();
    wndClass.lpszClassName    
=  pThis -> GetRegisterClassName();
    AUX_ASSERT_FAILED_RETURN_VALUE(AuxRegisterWindowClass(
& wndClass), FALSE);
    AUX_ASSERT_FAILED_RETURN_VALUE(
this -> CreateEx(dwExStyle, pThis -> GetRegisterClassName(), lpszWindowName, dwStyle, rect, pParentWnd, nID, lpParam), FALSE);

    
return  TRUE;
}

template
< typename T >
void  CAuxWindowT < T > ::DoDataExchange(CDataExchange *  pDX)
{
    CWnd::DoDataExchange(pDX);
}

BEGIN_TEMPLATE_MESSAGE_MAP(CAuxWindowT, T, CWnd)
    ON_WM_CREATE()
    ON_WM_PAINT()
    ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

template
< typename T >
int   CAuxWindowT < T > ::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    
int  nRet  =   1 ;

    __if_exists(T::InsideCreate)
    {
        DECLARE_TEMPLATE_THIS_POINTER(T, pThis);
        nRet 
=  pThis -> InsideCreate(lpCreateStruct);
    }
    
return  nRet;
}

template
< typename T >
void  CAuxWindowT < T > ::OnPaint()
{
    __if_exists(T::InsidePaint)
    {
        DECLARE_TEMPLATE_THIS_POINTER(T, pThis);
        pThis
-> InsidePaint();
    }

    __if_not_exists(T::InsidePaint)
    {
        CPaintDC dc(
this );
    }
}

template
< typename T >
BOOL CAuxWindowT
< T > ::OnEraseBkgnd(CDC *  pDC)
{
    __if_not_exists(T::InsideEraseBkgnd)
    {
        
return  CWnd::OnEraseBkgnd(pDC);
    }

    DECLARE_TEMPLATE_THIS_POINTER(T, pThis);
    
return  pThis -> InsideEraseBkgnd(pDC);
}

 

 这种封装很大的问题在于CWnd的消息映射宏只能映射到自己类中的某个方法,故而我只有在封装中加了一层转发接口,在这里调用派生类的相应的方法(如果有的话).如果完全定制BEGIN_MESSAGE_MAP/ END_MESSAGE_MAP宏使其保存指向派生类的方法,可以实现,但改动实在较大(不亚于自己重头开始写一个窗口类了),而且代码复用的优点也削弱了不少。

派生类的定义:代码

class  CFadeWindow :  public  CAuxWindowT < CFadeWindow >
{
    DECLARE_DYNAMIC(CFadeWindow)

public :
    CFadeWindow();   
//  标准构造函数
     virtual   ~ CFadeWindow();

public :
    LPCTSTR GetRegisterClassName()
    {
         
return  _T( " SinaShowFadeWindow " );
    }

    
int   InsideCreate(LPCREATESTRUCT lpCreateStruct);

    
void  InsidePaint();

    BOOL InsideEraseBkgnd(CDC
*  pDC);
};
 

// .cpp

IMPLEMENT_DYNAMIC(CFadeWindow, CAuxWindowT<CFadeWindow>)  


 代码注解:__if_exists和__if_not_exists用于判断某个标识符是否存在,其不能与else共用,所以提供2个相反的关键字。

             CAuxInitWinStruct:用于初始化Windows结构体的封装

             定义如下:

             代码

     //
    
//  封装Windows常用的结构体
    
//  自动进行清零操作和设置Windows结构体的cbSize字段
    
//
    template < typename TBase >
    
class   CAuxInitWinStruct :  public  TBase
    {
    
public :
        CAuxInitWinStruct()
        {
            ::ZeroMemory( this sizeof (TBase));
            
this -> cbSize    =    sizeof (TBase);
        }

        CAuxInitWinStruct( const  TBase &  var)
        {
            memcpy( this & var,  sizeof (TBase));
        }
    };

 

     AuxRegisterWindowClass:窗口类注册实现, 代码如下:

         代码

//  注册窗口类
    inline BOOL  AuxRegisterWindowClass( const  WNDCLASSEX *  pWndClass)
    {
        ATLASSERT(pWndClass  !=  NULL);

        BOOL  bSuccess   =   TRUE;

        
//  先检测窗口是否注册过
        WNDCLASSEX wndClassDummy;
        BOOL bRegistered  =  ::GetClassInfoEx(pWndClass -> hInstance, pWndClass -> lpszClassName,  & wndClassDummy);

        
if  ( ! bRegistered  ||  (wndClassDummy.lpfnWndProc  !=  pWndClass -> lpfnWndProc))
        { 
            
//  如果未注册或者注册的窗口过程不是本地的函数地址, 则重新注册
             if  (bRegistered)
            {
                
//  如果已注册 则先取消注册
                ::UnregisterClass(wndClassDummy.lpszClassName, pWndClass -> hInstance);
            }

            
//  注册窗口
            bSuccess  =  (::RegisterClassEx(pWndClass)  !=   0 ?  TRUE : FALSE;
        }

        
return  bSuccess;
    }

 

 

 

 

 

你可能感兴趣的:(模板)