zoukankan      html  css  js  c++  java
  • [MFC.Windows程序设计(第2版) 第一章

    1,windows编程模型如下图:

    2,  windows的消息有成百上千种,以下列举10个:

    3,消息处理函数的四个参数:窗口句柄(表示消息属于哪个窗口,32值。该窗口句柄引用一个数据结构,数据结构存储窗口的大小,风格,在屏幕的位置等信息)、消息ID、wParam、lParam。后两个存储消息的信息。

    4,m_开头表示成员变量。

     5,API程序和MFC程序的区别:

    6,MFC的文档/视图体系结构很重要,想要用MFC的高级特性就必须掌握这些。从第9章开始接触这个。

    7,MFC类的分层结构:

    CObject类是MFC的祖先类。主要提供三个特性:串行化、运行时类信息、诊断和调试。具体要后面慢慢熟悉。

    8,并非所有的MFC函数都是成员函数。以Afx开头的函数是MFC提供的全局函数。部分如下图:

    9,MFC的执行流程。非常关键,必须弄懂。

    MFC程序执行,操作系统将程序加载到内存,执行AfxWinMain函数(相当于win32的WinMain函数)。这个函数会将操作系统传过来的hInstance、nCmdShow等参数传递给全局变量theApp(这个通常是这样命名的,也可以命名为其他)的数据成员。那有人会问,这个theApp是什么时候创建的。其实这个theApp是应用程序全局变量。会在程序一开始运行就在内存创建好。现在只是给他的数据成员赋值。赋值完成后,就调用theApp的InitInstance函数。这个函数就相当于是MFC的入口函数了。当然调用这个函数是不需要传递参数的。因为这个函数是theApp的成员函数,可以使用theApp的数据成员(之前已经赋值了,现在当然可以直接使用那些被赋值过的数据成员了)。这个函数做一些初始化工作后,要返回一个bool值给AfxWinMain函数。如果返回值是false,则程序结束。如果返回值是true,则AfxWinMain会调用pThread->run()函数。这个函数执行消息循环,并向应用程序窗口发送消息。消息循环重复执行,直到遇到WM_QUIT消息,run才跳出循环。然后调用ExitInstance函数(一些清理工作)。然后AfxWinMain执行return语句结束整个程序。

    10,hello.h

     1 class CMyApp : public CWinApp
     2 {
     3 public:
     4     virtual BOOL InitInstance ();
     5 };
     6 
     7 class CMainWindow : public CFrameWnd
     8 {
     9 public:
    10     CMainWindow ();
    11 
    12 protected:
    13     afx_msg void OnPaint ();
    14     DECLARE_MESSAGE_MAP ()
    15 };

    hello.cpp

     1 #include <afxwin.h>
     2 #include "Hello.h"
     3 
     4 CMyApp myApp;
     5 
     6 /////////////////////////////////////////////////////////////////////////
     7 // CMyApp member functions
     8 
     9 BOOL CMyApp::InitInstance ()
    10 {
    11     m_pMainWnd = new CMainWindow;
    12     m_pMainWnd->ShowWindow (m_nCmdShow);
    13     m_pMainWnd->UpdateWindow ();
    14     return true;
    15 }
    16 
    17 /////////////////////////////////////////////////////////////////////////
    18 // CMainWindow message map and member functions
    19 
    20 BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
    21     ON_WM_PAINT ()
    22 END_MESSAGE_MAP ()
    23 
    24 CMainWindow::CMainWindow ()
    25 {
    26     Create (NULL, _T ("The Hello Application"));
    27 }
    28 
    29 void CMainWindow::OnPaint ()
    30 {
    31     CPaintDC dc (this);
    32     
    33     CRect rect;
    34     GetClientRect (&rect);
    35 
    36     dc.DrawText (_T ("Hello, MFC"), -1, &rect,
    37         DT_SINGLELINE | DT_CENTER | DT_VCENTER);
    38 }

    上面的代码中,重点讲下

    m_pMainWnd->ShowWindow (m_nCmdShow);
    m_pMainWnd->UpdateWindow ();
    这里调用了showWindow后,主窗口按理说应该显示,事实上,是通过发送WM_PAINT消息给应用程序来响应消息的。当应用程序收到消息WM_PAINT,会调用消息处理函数OnPaint函数。
    对于OnPaint函数,通过CPaintDC对象调用DrawText函数来绘制文本。CPaintDC是CDC的子类。CDC封装了windows的设备环境。在CPaintDC的构造函数会调用::BeginPaint()函数,在CPaintDC析构函数会调用::EndPaint()函数。这样做是为了能够将WM_PAINT消息从
    消息队列中取出。因为不调用
    ::BeginPaint()和::EndPaint()函数,WM_PAINT消息是不能从消息队列中取出的。CPaintDC对象dc可以设置字体,文本颜色等。此处没有使用这些功能。
    GetClientRect方法获取窗口中客户区的坐标顶点位置并赋给rect对象。然后通过DrawText函数,就能找到窗口客户区的正中间绘制文本"Hello,MFC"。

    11,消息映射的工作原理。非常重要,必须掌握。
    hello.h中的声明: DECLARE_MESSAGE_MAP ()
    hello.cpp中的定义:
     BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
         ON_WM_PAINT ()
     END_MESSAGE_MAP ()

    这些宏就是实现消息映射的关键。

    DECLARE_MESSAGE_MAP的声明给hello.h添加了三个数据成员:一个结构数组_messageEntries(包含消息及消息处理函数指针),一个静态结构messageMap(该结构包含两个指针,一个指向类中的_messageEntries数组的指针,一个指向父类messageMap结构的指针)。,一个名为
    GetMessageMap的虚函数(该函数返回messageMap的指针)。

    下图是BEGIN_MESSAGE_MAP的实现:(afxwin.h)
     1 #define BEGIN_MESSAGE_MAP(theClass, baseClass) 
     2     PTM_WARNING_DISABLE 
     3     const AFX_MSGMAP* theClass::GetMessageMap() const 
     4         { return GetThisMessageMap(); } 
     5     const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() 
     6     { 
     7         typedef theClass ThisClass;                           
     8         typedef baseClass TheBaseClass;                       
     9         static const AFX_MSGMAP_ENTRY _messageEntries[] =  
    10         {

    很明显,我们写在BEGIN_MESSAGE_MAP宏后面的代码会被添加到_messageEntries结构数组中。下面是END_MESSAGE_MAP宏的定义:(afxwin.h)

    1 #define END_MESSAGE_MAP() 
    2         {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } 
    3     }; 
    4         static const AFX_MSGMAP messageMap = 
    5         { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; 
    6         return &messageMap; 
    7     }

    第一行的意思是添加一个NULL条目。表示结构数组的结束。

    从上面这些可以看出:一旦应用程序收到窗口的消息,会先调用WindowProc函数(由Cwnd继承)。WindowProctor又会调用OnWndMsg。OnWndMsg又会调用GetMessageMap获取指向CMainWindow::messageMap指针。最终就能通过这个指针找到消息处理函数。如果在本类中没找到消息对应的消息处理函数,就会去通过CMainWindow::messageMap找到父类的messageMap指针,从而找到父类的消息映射表。从而一次一次往父类找。最终的查找过程见下图:

     12,_T宏的作用:

    如果不适用_T宏,将字符串常量编码为"Hello, MFC",编译器将使用ANSI字符组成该字符串,如果将字符串常量编码为L"Hello,MFC",编译器将使用Unicode字符组成该字符串。这样导致的问题就是编写的代码与字符集有关了,不适于跨平台性。因为不同的平台使用的字符集不同,就需要维护两套代码来分别支持ANSI字符集和Unicode字符集。

    使用MFC的_T宏,可以使得编译器根据代码是否定义_UNICODE宏来确定使用什么字符集。如果定义了_UNICODE宏,就使用Unicode字符集,如果没有定义_UNICODE宏,就使用ANSI字符集。这样的代码是跨平台的。因为只需要维护一份代码。只需要编译的时候定义或者不定义_UNICODE宏就能产生不同平台的代码了。

    当然也不是使用_T宏就可以一劳永逸了。这只是使得字符串常量支持跨平台。还有一些接口,一些变量类型都需要使用跨平台的类型,才能实现整个代码都是跨平台的。当然原理都和这个一样。下面看个例子。

     
     


  • 相关阅读:
    多表关联查询_resultMap_集合对象
    mybatis多表关联查询之resultMap单个对象
    十二.filter
    十二.函数式编程
    十一.列表生成式
    十,迭代
    九.高级特性
    八.函数
    七.条件判断和循环
    六.使用list和tuple
  • 原文地址:https://www.cnblogs.com/zhoubiao20170424/p/7691873.html
Copyright © 2011-2022 走看看