MFC窗口的创建

 1.MFC窗口类CWnd

在Windows系统里,一个窗口的属性分两个地方存放:一部分放在“窗口类”里头,如上所述的在注册窗口时指定;另一部分放在Windows Object本身,如:窗口的尺寸,窗口的位置(X,Y轴),窗口的Z轴顺序,窗口的状态(ACTIVE,MINIMIZED,MAXMIZED,RESTORED…),和其他窗口的关系(父窗口,子窗口…),窗口是否可以接收键盘或鼠标消息,等等。

为了表达所有这些窗口的共性,MFC设计了一个窗口基类CWnd。有一点非常重要,那就是CWnd提供了一个标准而通用的MFC窗口过程,MFC下所有的窗口都使用这个窗口过程。至于通用的窗口过程却能为各个窗口实现不同的操作,那就是MFC消息映射机制的奥秘和作用了。这些,将在后面有关章节详细论述。

CWnd提供了一系列成员函数,或者是对Win32相关函数的封装,或者是CWnd新设计的一些函数。这些函数大致如下。

 

(1)窗口创建函数

这里主要讨论函数Create和CreateEx。它们封装了Win32窗口创建函数::CreateWindowEx。Create的原型如下:

BOOL CWnd::Create(LPCTSTR lpszClassName,

LPCTSTR lpszWindowName, DWORD dwStyle,

const RECT& rect,

CWnd* pParentWnd, UINT nID,

CCreateContext* pContext)

Create是一个虚拟函数,用来创建子窗口(不能创建桌面窗口和POP UP窗口)。CWnd的基类可以覆盖该函数,例如边框窗口类等覆盖了该函数以实现边框窗口的创建,视类则使用它来创建视窗口。

 

Create调用了成员函数CreateEx。CWnd::CreateEx的原型如下:

BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

LPCTSTR lpszWindowName, DWORD dwStyle,

int x, int y, int nWidth, int nHeight,

HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)

CreateEx有11个参数,它将调用::CreateWindowEx完成窗口的创建,这11个参数对应地传递给::CreateWindowEx。参数指定了窗口扩展风格、“窗口类”、窗口名、窗口大小和位置、父窗口句柄、窗口菜单和窗口创建参数。

CreateEx的处理流程将在后面4.4.1节讨论窗口过程时分析。

窗口创建时发送WM_CREATE消息,消息参数lParam指向一个CreateStruct结构的变量,该结构有11个域,其描述见后面4.4.1节对窗口过程的分析,Windows使用和CreateEx参数一样的内容填充该变量。

 

(2)窗口销毁函数

例如:

DestroyWindow函数 销毁窗口

PostNcDestroy( ),销毁窗口后调用,虚拟函数

 

 

(3)用于设定、获取、改变窗口属性的函数,例如:

SetWindowText(CString tiltle) 设置窗口标题

GetWindowText() 得到窗口标题

SetIcon(HICON hIcon, BOOL bBigIcon);设置窗口像标

GetIcon( BOOL bBigIcon ) ;得到窗口像标

GetDlgItem( int nID);得到窗口类指定ID的控制子窗口

GetDC(); 得到窗口的设备上下文

SetMenu(CMenu *pMenu); 设置窗口菜单

GetMenu();得到窗口菜单

 

 

(4)用于完成窗口动作的函数

用于更新窗口,滚动窗口,等等。一部分成员函数设计成或可重载(Overloaded)函数,或虚拟(Overridden)函数,或MFC消息处理函数。这些函数或者实现了一部分功能,或者仅仅是一个空函数。如:

  •  

  • 有关消息发送的函数:

SendMessage( UINT message,WPARAM wParam = 0, LPARAM lParam = 0 );

给窗口发送发送消息,立即调用方式

PostMessage(( UINT message,WPARAM wParam = 0, LPARAM lParam = 0 );

给窗口发送消息,放进消息队列

  •  

  • 有关改变窗口状态的函数

MoveWindow( LPCRECT lpRect, BOOL bRepaint = TRUE );

移动窗口到指定位置

ShowWindow(BOOL );显示窗口,使之可见或不可见

….

  •  

  • 实现MFC消息处理机制的函数:

virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam ); 窗口过程,虚拟函数

 

virtual BOOL OnCommand( WPARAM wParam, LPARAM lParam );处理命令消息

  •  

  • 消息处理函数:

OnCreate( LPCREATESTRUCT lpCreateStruct );MFC窗口消息处理函数,窗口创建时由MFC框架调用

OnClose();MFC窗口消息处理函数,窗口创建时由MFC框架调用

  •  

  • 其他功能的函数

CWnd的导出类是类型更具体、功能更完善的窗口类,它们继承了CWnd的属性和方法,并提供了新的成员函数(消息处理函数、虚拟函数、等等)。

常用的窗口类及其层次关系见图1-1。

MFC窗口的创建_第1张图片

 

 

    2.在MFC下创建一个窗口对象

MFC下创建一个窗口对象分两步,首先创建MFC窗口对象,然后创建对应的Windows窗口。在内存使用上,MFC窗口对象可以在栈或者堆(使用new创建)中创建。具体表述如下:

  •  

  • 创建MFC窗口对象。通过定义一个CWnd或其派生类的实例变量或者动态创建一个MFC窗口的实例,前者在栈空间创建一个MFC窗口对象,后者在堆空间创建一个MFC窗口对象。

     

  • 调用相应的窗口创建函数,创建Windows窗口对象。

例如:在前面提到的AppWizard产生的源码中,有CMainFrame(派生于CMDIFrame(SDI)或者CMDIFrameWnd(MDI))类。它有两个成员变量定义如下:

CToolBar m_wndToolBar;

CStatusBar m_wndStatusBar;

当创建CMainFrame类对象时,上面两个MFC Object也被构造。

CMainFrame还有一个成员函数

OnCreate(LPCREATESTRUCT lpCreateStruct),

它的实现包含如下一段代码,调用CToolBar和CStatusBar的成员函数Create来创建上述两个MFC对象对应的工具栏HWND窗口和状态栏HWND窗口:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (!m_wndToolBar.Create(this) ||

!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

{

TRACE0("Failed to create toolbar\n");

return -1; // fail to create

}

 

if (!m_wndStatusBar.Create(this) ||

!m_wndStatusBar.SetIndicators(indicators,

sizeof(indicators)/sizeof(UINT)))

{

TRACE0("Failed to create status bar\n");

return -1; // fail to create

}

}

关于工具栏、状态栏将在后续有关章节作详细讨论。

在MFC中,还提供了一种动态创建技术。动态创建的过程实际上也如上所述分两步,只不过MFC使用这个技术是由框架自动地完成整个过程的。通常框架窗口、文档框架窗口、视使用了动态创建。介于MFC的结构,CFrameWnd和CView及其派生类的实例即使不使用动态创建,也要用new在堆中分配。理由见窗口的销毁(2.2.5节)。

至于动态创建技术,将在下一章具体讨论。

在Windows窗口的创建过程中,将发送一些消息,如:

在创建了窗口的非客户区(Nonclient area)之后,发送消息WM_NCCREATE;

在创建了窗口的客户区(client area)之后,发送消息WM_CREATE;

窗口的窗口过程在窗口显示之前收到这两个消息。

如果是子窗口,在发送了上述两个消息之后,还给父窗口发送WM_PARENATNOTIFY消息。其他类或风格的窗口可能发送更多的消息,具体参见SDK开发文档。

 

    3.MFC窗口的使用

MFC提供了大量的窗口类,其功能和用途各异。程序员应该选择哪些类来使用,以及怎么使用他们呢?

直接使用MFC提供的窗口类或者先从MFC窗口类派生一个新的C++类然后使用它,这些在通常情况下都不需要程序员提供窗口注册的代码。是否需要派生新的C++类,视MFC已有的窗口类是否能满足使用要求而定。派生的C++类继承了基类的特性并改变或扩展了它的功能,例如增加或者改变对消息、事件的特殊处理等。

主要使用或继承以下一些MFC窗口类(其层次关系图见图1-1):

框架类CFrameWnd,CMdiFrameWnd;

文档框架CMdiChildWnd;

视图CView和CView派生的有特殊功能的视图如:列表CListView,编辑CEditView,树形列表CTreeView,支持RTF的CRichEditView,基于对话框的视CFormView等等。

对话框CDialog。

通常,都要从这些类派生应用程序的框架窗口和视窗口或者对话框。

 

工具条CToolBar

状态条CStatusBar

其他各类控制窗口,如列表框CList,编辑框CEdit,组合框CComboBox,按钮Cbutton等。

通常,直接使用这些类。

 

 

    4.在MFC下窗口的销毁

窗口对象使用完毕,应该销毁。在MFC下,一个窗口对象的销毁包括HWND窗口对象的销毁和MFC窗口对象的销毁。一般情况下,MFC编程框架自动地处理了这些。

(1)对CFrameWnd和CView的派生类

这些窗口的关闭导致销毁窗口的函数DestroyWindow被调用。销毁Windows窗口时,MFC框架调用的最后一个成员函数是OnNcDestroy函数,该函数负责Windows清理工作,并在最后调用虚拟成员函数PostNcDestroy。CFrameWnd和CView的PostNcDestroy调用delete this删除自身这个MFC窗口对象。

所以,对这些窗口,如前所述,应在堆(Heap)中分配,而且,不要对这些对象使用delete操作。

 

(2)对Windows Control窗口

在它们的析构函数中,将调用DestroyWidnow来销毁窗口。如果在栈中分配这样的窗口对象,则在超出作用范围的时候,随着析构函数的调用,MFC窗口对象和它的Windows window对象都被销毁。如果在堆(Heap)中分配,则显式调用delete操作符,导致析构函数的调用和窗口的销毁。

所以,这种类型的窗口应尽可能在栈中分配,避免用额外的代码来销毁窗口。如前所述的CMainFrame的成员变量m_wndStatusBar和m_wndToolBar就是这样的例子。

(3)对于程序员直接从CWnd派生的窗口

程序员可以在派生类中实现上述两种机制之一,然后,在相应的规范下使用。

你可能感兴趣的:(VC)