AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > VC编程

VC初学者入门系列之一:窗口类的诞生

51自学网 2015-08-30 http://www.wanshiok.com

三、MFC中的窗口类
  当你看到这里,也许你可能会感到奇怪:我在用MFC向导做程序时,并没有进行什么窗口类的填写和注册吗?是的,你没有,但是向导帮你做了。在展示向导是怎么做的之前,请让我先介绍一下预先知识。
  在MFC系统中定义了五个默认的窗口类(这里不包括AFX_WNDCOMMCTLS_REG),分别定义在AFXIMPL.h中:   #define AFX_WND_REG          (0x0001)
  #define AFX_WNDCONTROLBAR_REG    (0x0002)
  #define AFX_WNDMDIFRAME_REG      (0x0004)
  #define AFX_WNDFRAMEORVIEW_REG    (0x0008)
  #define AFX_WNDDOLECONTROL_REG    (0x0020)

在WINCORE.cpp定义了这些窗口类对应的字符串名称:  const TCHAR _afxWnd[] = AFX_WND;
  const TCHAR _afxWndControlBar[] = AFX_WNDCONTROLBAR;
  const TCHAR _afxWndMDIFrame[] = AFX_WNDMDIFRAME;
  const TCHAR _afxWndFrameOrView[] = AFX_WNDFRAMEORVIEW;
  const TCHAR _afxWndOleControl[] = AFX_WNDOLERONTROL;

在AFXIMPL.h中定义了五个AFX_XXX对应的字符串:  #define AFX_WND         AFX_WNDCLASS("WND")
  #define AFX_WNDCONTROLBAR  AFX_WNDCLASS("ControlBar")
  #define AFX_WNDMDIFRAME   AFX_WNDCLASS("MDIFrame")
  #define AFX_WNDFRAMEORVIEW AFX_WNDCLASS("FrameOrView")
  #define AFX_WNDOLECONTROL  AFX_WNDCLASS("OleControl")

  看到这里也许有些心急了,其实上面一堆代码只是定义了五个默认窗口类的字符串名称和二进制名称,具体注册行为在全局函数AfxDeferRegisterClass中: #define AfxDeferRegisterClass(fClass) /
((afxRegisteredClasses & fClass) ? TRUE:AfxEndDeferRegisterClass(fClass)
  #define afxRegisteredClasses AfxGetModuleState()->m_fRegisteredClasses

  BOOL AFXAPI AfxEndDeferRegisterClass(short fClass)
  {
    WNDCLASS wndCls;
    wndCls.lpfnWndProc = DefWindowProc;
    if(fClass & AFX_WND_REG)
    {
      wndCls.lpszClassName=_afxWnd;
      AfxRegisterClass(&wndCls);
    }else if(fClass & AFX_WNDOLECONTROL_REG)
    {
      wndCls.lpszClassName=_afxWndOleControl;
      AfxRegisterClass(&wndCls);
    }else if(fClass & AFX_WNDCONTROLBAR_REG)
    {
      wndCls.lpszClassName=_afxWndControlBar;
      AfxRegisterClass(&wndCls);
    }else if(fClass & AFX_WNDMDIFRAME_REG)
    {
      RegisterWithIcon(&wndCls,_afxWndMDIFrame,AFX_IDI_MDIFRAME);
    }else if(fClass & AFX_WNDFRAMEORVIEW_REG)
    {
  RegisterWithIcon(&wndCls,_afxWndFrameOrView,AFX_IDI_STD_FRAME);
    }else if(fClass & AFX_WNDCOMMCTLS_REG)
    {
      InitCommonControls();
    }
  }

  从上面的代码可以看出,AfxDeferRegisterClass函数首先判断该窗口类是否注册,如已注册则直接返回,否则调用AfxEndDeferRegisterClass进行注册,即注册要求的默认窗口类。其中RegisterWithIcon和InitCommonControls最终也是转化为调用AfxRegisterClass,而AfxRegisterClass函数调用RegisterClass进行注册,啊,终于看到SDK中的RegisterClass了,看到它总有一种亲切感!
  有了上面的知识,我们就可以很容易摸清MFC是怎样注册窗口类的了!我们知道Windows上所有看得见的东西,在MFC中都是继承于CWnd类的,而CWnd类创建窗口的成员函数是Create和CreateEx,由于Create最终是调用CreateEx,所以我们只需要看CreateEx函数就行了:   BOOL CWnd::CreateEx(DWORD dwExStyle, LPCSTSTR lpszClassName,
            …… LPVOID lpParam)
  {
   CREATESTRUCT cs;
   cs.dwExStyle = dwExStyle;
   … …
   cs.lpCreateParams = lpParam;

   PreCreateWindow(cs);
   AfxHookWindowCreate(this);
   HWND hWnd=::CreateWindowEx(cs.dwStyle,cs.lpszClass,…,cs.lpCreateParams);
   ……
  }

  啊,一看到CreateWindowEx,亲切感又来了,这不是和SDK中的CreateWindow一样嘛,是创建窗口!既然这样,那么注册窗口肯定在该函数之前,会是谁呢?如果你做过一点MFC程序,你就会对将眼光停留PreCreateWindow上。对!就是它了。
  PreCreateWindow函数是CWnd类的一个虚拟函数,提供程序设置待创建窗口的属性(包括窗口类),这样继承于CWnd的类都可以按照自己的要求在PreCreateWindow中设置自己的属性了,而且我们看到MFC也是这样做的: BOOL CWnd::PreCreateWindow(CREATESTRUCT &cs)
{
   if(cs.lpszClass = = NULL)
   {
     AfxDeferRegisterClass(AFX_WND_REG);
     cs.lpszClass = _afxWnd;
   }
   return TRUE;
}

BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT &cs)
{
   if(cs.lpszClass = = NULL)
   {
     AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG);
    cs.lpszClass = _afxWndFrameOrView;
   }
   return TRUE;
}

BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT &cs)
{
  if(cs.lpszClass = = NULL)
  {
   AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG);
   cs.lpszClass = _afxWndMDIFrame;
  }
}

BOOL CMDIChildWnd::PreCreateWindow(CREATESTRUCT &cs)
{
   return CFrameWnd::PreCreateWindow(cs);
}

BOOL CView::PreCreateWindow(CREATESTRUCT &cs)
{
   if(cs.lpszClass = = NULL)
   {
     AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG);
     cs.lpszClass = _afxWndFrameOrView;
   }
}

就是通过继承的方法,MFC实现常用类的窗口注册(代码并不完全,是从MFC中抽取对我们有意义的一部分代码)。

四、在MFC中注册自己的窗口类
  在MFC中创建一个窗口,就必须是继承于CWnd类的,这样你的CMyWnd类自然就有了PreCreateWindow方法。你想注册有自己个性的窗口类,那么就在该函数中进行吧。也就是在PreCreateWindow函数中注册自己的窗口类,然后将窗口类的类名以及待创建窗口的其它属性(见CREATESTRUCT结构)填写cs,然后返回系统,供系统创建你的窗口。


 

 
 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。

上一篇:用Visual C++编写电子邮件程序  下一篇:VC初学者入门系列之二:消息循环