⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 0302.htm

📁 c语言经典教程
💻 HTM
📖 第 1 页 / 共 2 页
字号:
  ASSERT_VALID(pDoc);<BR>
  // TODO: add draw code for native data here<BR>
  <b>CString s("Hello");</b><BR>
  <b>pDC->TextOut(0,20,s);</b><BR>
}<BR>
  编译并运行该程序,弹出如下图窗口,在窗口左上角显示“Hello”。<BR>
<p align="center"><span style="FONT-SIZE: 9pt"><img height="525" width="765" alt="显示“Hello”的窗口" src="030204.jpg" ></span></p>
<p align="center"><span style="FONT-SIZE: 9pt">图3.2.4 显示“Hello”的窗口</span></p>
  到现在为止,我们只写了两行代码,就完成了SDK下需要几百行程序才能完成的工作。这应当归功于Visual Studio提供的AppWizard以及MFC框架在幕后所作的大量工作。<BR>
</p>
<H3><a name='04'>四、应用程序执行机制</a></H3>
<p>
1、WinMain函数<BR>
  在DOS下,程序的执行是从main函数开始的。在Windows下,对应的函数是WinMain。<BR>
  但是,如果浏览TestMsg程序的所有的方法和全局函数,是找不到WinMain函数的。<BR>
  MFC考虑到典型的Windows程序需要的大部分初始化工作都是标准化的,因此把WinMain函数隐藏在应用程序的框架中,编译时会自动将该函数链接到可执行文件中。<BR>
  程序员可以重写WinMain函数,但一般不需要这么做。<BR><BR>
  应用程序执行时,Windows自动调用应用程序框架内部的WinMain函数。<BR>
  WinMain函数会查找该应用程序的一个全局构造对象,这个对象是由CWinApp派生类构造的,有且只有一个。它是一个全局对象,因此在程序启动时,它就已经被构造好了。<BR>
  随后,WinMain将调用这个对象的InitApplication和InitInstance成员函数,完成应用程序实例的初始化工作。<BR>
  随后,WinMain调用Run成员函数,运行应用程序的消息循环。<BR>
  在程序结束时,WinMain调用AfxWinTerm函数,做一些清理工作。<BR><BR>
2、应用程序类<BR>
  每个应用程序必须从CWinApp派生出自己的应用程序类,并定义一个全局的对象。<BR>
  该应用程序类包含了Windows下应用程序的初始化、运行和结束过程。基于框架建立的应用程序必须有一个(且只能有一个)从CWinApp派生的类的对象。<BR>
  在TestMsg程序中,我们从CWinApp中派生出一个CTestMsgApp类,并定义了一个全局对象theApp。CTestMsgApp类在TestMsg.cpp中定义。<BR>
  要访问应用程序类构造的对象,可以调用全局函数AfxGetApp()。AfxGetApp()返回一个指向全局对象的指针。可以通过对它进行强制类型转换,转换为我们派生的应用程序类。<BR>
  例如:CTestMsgApp* pApp=(CTestMsgApp*)AfxGetApp();<BR><BR>
  在CWinApp的派生类中,必须重载InitInstance函数,因为CWinApp并不知道应用程序需要什么样的窗口,它可以多文档窗口、单文档窗口,也可以是基于对话框的。<BR>
  InitInstance函数主要完成以下工作:设置注册数据库,载入标准设置(最近打开文件列表等)、注册文档模板。接着,处理命令行参数,显示主窗口,然后返回、进入消息循环。<BR><BR>
3、Run成员函数<BR>
  WinMain在初始化应用程序实例后,就调用Run函数来处理消息循环。<BR>
  Run成员函数不断执行消息循环,检查消息队列中有没有消息。<BR>
  如果有消息,Run将其派遣,交由框架去处理,然后返回继续消息循环。如果没有消息,Run将调用OnIdle来做用户或框架可能需要在空闲时才做的工作。<BR>
  如果既没有消息要处理,也没有空闲时的处理工作要做,则应用程序将一直等待,直到有事件发生。<BR>
  当应用程序结束时,Run将调用ExitInstance。消息循环的流程图如下图0所示。<BR>
<p align="center"><span style="FONT-SIZE: 9pt"><img height="435" width="335" alt="Run成员函数的消息循环" src="030205.jpg" ></span></p>
<p align="center"><span style="FONT-SIZE: 9pt">图3.2.5 Run成员函数的消息循环</span></p>
4、关闭应用程序<BR>
  用户可以通过选择File-Exit菜单或点主窗口的关闭按钮,关闭主框架窗口,来终止应用程序。<BR>
  此时,应用程序类首先删除m_pMainWnd主框架窗口对象,然后退出Run函数,进而退出WinMain,在退出WinMain后删除TheApp对象。<BR>
</p>
<H3><a name='05'>五、框架窗口</a></H3>
<p>
1、框架窗口<BR>
  框架窗口为应用程序的用户界面提供结构框架,它是应用程序的主窗口,负责管理其包容。一个应用程序的最顶层的框架窗口是应用程序启动时创建的第一个窗口。<BR>
  MFC提供三种类型的框架窗口:单文档窗口,多文档窗口(MDI),对话框。在AppWizard的第一个对话框中,就提供了选项,让用户选择应用程序是基于单文档、多文档还是对话框的。<BR>
  MFC单文档窗口一次只能打开一个文档框架窗口,而MDI应用程序运行时,在应用程序的一个实例中打开多个文档框架窗口,这些窗口称作子窗口(Child Window)。这些文档可以是同一类型的,也可以是不同类型的。如Visual Studio就可以打开资源文件窗口和源程序窗口等不同类型的窗口。此时,激活不同类型的MDI子窗口,菜单也将相应变化。<BR>
  MFC提供了类CFrameWnd、CMDIFrameWnd、CMDIChildWnd和CDialog 分别用于支持单文档窗口、多文档窗口和对话框。<BR>
  要生成一个单文档窗口,主窗口就必须从CFrameWnd派生;要生成一个多文档窗口,主窗口就必须从CMDIFrameWnd派生,而且其中的子窗口必须从CMDIChildWnd派生出来;而基于对话框的窗口程序就要从CDialog派生出主窗口类。<BR>
<H4>CFrameWnd</H4>
  用于SDI框架窗口,形成单个文档及其视的边框。框架窗口既是应用程序的主框架窗口,也是当前文档对应的视图的边框。<BR>
<H4>CMDIFrameWnd</H4>
  用于MDI应用程序的主框架窗口。主框架窗口是所有MDI文档窗口的容器,并与它们共享菜单条。MDI框架窗口是出现在桌面中的顶层窗口。<BR>
<H4>CMDIChildWnd</H4>
  用于在MDI主框架窗口中显示打开的各个文档。每个文档及其视都有一个MDI子框架窗口,子框架窗口包含在MDI主框架窗口中。子框架窗口看起来类似一般的框架边框窗口,但它是包含在主框架窗口中,而不是位于桌面的,并且为主窗口所裁剪。而且MDI子窗口没有自己的菜单,它与主MDI框架窗口共享菜单。<BR>
<H4>CDialog</H4>
  对话框是一种特殊类型的窗口,它的边框一般不可以调整,而且内部包含一些控件窗口。<BR><BR>
<H4>子窗口</H4>
  子窗口就是具有WS_CHILD风格的窗口,且一定有一个父窗口。所有的控件都是子窗口。子窗口可以没有边框。子窗口被完全限制在父窗口内部。<BR>
<H4>父窗口</H4>
  父窗口就是拥有子窗口的窗口。<BR>
<H4>弹出式窗口</H4>
  具有WS_POPUP风格,它可以没有父窗口。这种窗口几乎什么都没有,可看作一个矩形区域。<BR><BR>
2、窗口的创建<BR>
  窗口的创建分为两步:<BR>
  第一步是用new创建一个C++的窗口对象,但是此时只是初始化窗口的数据成员,并没有真正创建窗口。<BR>
    //第一步:创建一个C++对象,其中CMainFrame是从CFrameWnd派生的对象。<BR>
    CMainFrame* pMyFrame=new CMainFrame();//用new操作符创建窗口对象<BR>
  或<BR>
    CMainFrame MyFrame;//定义一个窗口对象,自动调用其构造函数<BR><BR>
  第二步是创建窗口。<BR>
  CFrameWnd的Create成员函数把窗口给做出来,并将其HWND保存在C++对象的公共数据成员m_hWnd中。<BR>
    //第二步:创建窗口<BR>
    pMyFrame->Create(NULL,“My Frame Window”);<BR>
  或<BR>
    MyFrame.Create(NULL,“My Frame Window”);<BR>
  Create函数的原形如下:<BR>
  BOOL Create( LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle = WS_OVERLAPPEDWINDOW, const RECT& rect = rectDefault, CWnd* pParentWnd = NULL, LPCTSTR lpszMenuName = NULL, DWORD dwExStyle = 0, CCreateContext* pContext = NULL );<BR>
  Create函数第一个参数为窗口注册类名,它指定了窗口的图标和类风格。这里我们使用NULL做为其值,表明使用缺省属性。第二个参数为窗口标题。其余几个参数指定了窗口的风格、大小、父窗口、菜单名等。<BR>
  这个函数看起来比较复杂,对于CFrameWnd派生出来的窗口,我们可以使用LoadFrame从资源文件中创建窗口,它只需要一个参数。<BR>
    pMyFrame->LoadFrame(IDR_MAINFRAME);<BR>
  LoadFrame使用该参数从资源中获取许多默认值,包括主边框窗口的标题、图标、菜单、加速键等。但是,在使用LoadFrame时,必须确保标题字符串、图标、菜单、加速键等资源使用同一个ID标识符(如IDR_MAINFRAME)。<BR><BR>
  在MainFrm.cpp中,我们还看到CMainFrame类有一个OnCreate方法。当调用Create或CreateEx时,操作系统会向窗口发送一条WM_CREATE消息。这一函数就是用来响应WM_CREATE消息的。<BR>
  在OnCreate函数中,首先调用CFrameWnd的缺省处理方法OnCreate完成窗口创建工作。后面是应用程序主窗口的特定工作,如创建了工具条和状态栏等。可以在此处加入一些初始化工作,如从INI文件中载入设置,显示Splash Window(启动画面)等。<BR><BR>
3、关闭和销毁窗口<BR>
  框架窗口不仅维护窗口的创建,还管理着窗口的关闭和销毁过程。<BR>
  关闭窗口时,操作系统依次向被关闭的窗口发送WM_CLOSE和WM_DESTROY消息。<BR>
  WM_CLOSE消息的缺省处理函数OnClose将调用DestroyWindow,来销毁窗口;最后,框架调用窗口的析构函数作清理工作并删除C++窗口对象。<BR>
  不要使用C++的delete操作符来销毁框架窗口,而应当采用CWnd的DestroyWindow成员函数来销毁。<BR>
  DestroyWindow首先删除子窗口,再删除窗口本身。<BR>
  若窗口以变量方式产生(即在堆栈上分配内存),该窗口对象会被自动清除。若对象是用new操作符创建的(也就是在堆上分配内存的),则需要用户自己处理。<BR>
  OnClose()常用功能:保存窗口的一些状态、工具条状态,提示保存未保存的数据等等。<BR>
    void CMainFrame::OnClose()<BR>
    {<BR>
      SaveBarState( "MyDockState" );//保存工具条状态<BR>
      CFrameWnd::OnClose();<BR>
    }<BR><BR>
4、窗口激活<BR>
  活动窗口必定是一个没有父窗口的顶层窗口,包括框架窗口和对话框。<BR>
  当顶层窗口被激活时,Windows向窗口发送WM_ACTIVATE消息,对此消息的缺省处理是将活动窗口设为有输入焦点。<BR>
  输入焦点用于表示哪个窗口有资格接收键盘输入消息。带有输入焦点的窗口或是一个活动窗口,或者是该活动窗口的子窗口。<BR>
  当一个顶层窗口获得输入焦点时,Windows向该窗口发送WM_SETFOCUS消息,此窗口可将输入焦点重定位到它的子窗口上。子窗口不会自动获得输入焦点。失去输入焦点的窗口会收到WM_KILLFOCUS消息。当子窗口拥有输入焦点时,父窗口就不会处理键盘输入了。<BR>
</p>
</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -