【MFC】第3课 MFC程序框架学习笔记

第3MFC程序框架之一直接实践【参考资料:孙鑫VC++教学视频】

 

我们现在用VC6直接实践一下MFC编程: 

1、程序类型MFC AppWizard(exe)类型;

2、选择Single Document单文档

3、完成

 

虽然我们没有写一行代码,但是我们运行后,可以看到已经生成了一个对话框了,标准的对话框;

class view里面可以看到一些类:

CAoutDlg

cMainFraim

CTestApp

CTestView

CTestDoc

 

并且可以看到:

class CTestView : public CView

CTestView是从CView类里面派生出来的;

其他的类也是从相应的类里面派生出来的;

 

那么由编译器自动生成的对话框,有没有WinMain函数呢?

VC6安装目录下VC98里面MFC里面SRC文件夹里面,

搜索WinMain函数,在APPMODUL.cpp里面:

extern "C" int WINAPI

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

       LPTSTR lpCmdLine, int nCmdShow)

{

       // call shared/exported WinMain

       return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

这个函数就是我们原来的WinMain函数;

再继续查看:

TCHAR.h里面可以看到

#define _tWinMain   WinMain

真相大白,就是我们的WinMain函数;

 

 3MFC程序框架之二执行顺序【参考资料:孙鑫VC++教学视频】

 

class view里面可以看到一些类:

CAoutDlg

cMainFraim

CTestApp

CTestView

CTestDoc

 

那么我们的主函数和哪个类有关系,或者说被集成到哪个类里面了?

WinMain函数还是不是程序的入口函数呢?

 采用设置断点的方式找到执行顺序!

第一步:全局对象CTestApp theApp; Test.cppCTestApp类的实现文件】; //全局变量

第二步:CTestApp对象的构造函数;

第三步:_tWinMain函数;

 

★全局变量或者全局对象要先于main函数之前运行的;

★结论:在MFC程序中,WinMain还是入口函数;

★全局对象CTestApp   theApp唯一的表示我们的应用程序;

 

 

3MFC程序框架之三设计注册创建【参考资料:孙鑫VC++教学视频】

 

我们来研究WinMain函数:

extern "C" int WINAPI

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

       LPTSTR lpCmdLine, int nCmdShow)

{

       // call shared/exported WinMain

       return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

它实际上是调用了AfxWinMain函数;

Afx是什么意思?

是应用程序框架类的一堆函数,Application Frameworkx=没用,是为了美观方便加上去的

是一些全局函数,用在类之间的连接;

可以在每一个类中调用;

 

WinMain.cpp源文件里面,我们找到了AfxWinMain函数。

★在这个函数里面完成了设计、注册、创建窗口;

设计窗口时MFC已经设计了一些缺省的窗口,注册时预先已经完成了;

注册窗口的函数是:AfxEndDeferRegisterClassWINCORE.cpp

在注册函数里面可以看到各种各样的窗口;

在注册函数里是调用了AfxRegisterClass来注册的,这是个框架类的全局函数,在类里面可以直接调用;#Define   AfxDeferRegisterClass    AfxEndDeferRegisterClass

 

 

整个过程:设计(mfc设计好了),注册,产生,显示,更新,消息循环。

 

段点执行顺序:

1. CTestApp   theApp  全局对象    来启动这个应用程序,this指针指向这个全局对象。如果不用这个全局对象。编译不会出错,但是运行的时候会出错。

2. CTestApp::CTestApp()析构函数   CWinApp完成了初始化工作。同时把子类的指针保存起来。

3.WinMain函数, 会跳AFxWinMain函数,

 AFxWinMain函数里会执行子类指针,调用InitInstance()【是个虚函数】会调用子类的InitInstance()  完成窗口类的注册,创建,显示,更新,等等。

4.会调用 AfxEndDeferRegisterClass

5.CMainFranme ::PreCreateWindow  再次调用AfxDeferRegisterClass去注册我们的窗口类。

6. AfxEndDeferRegisterClass

7.CFrameWnd::Create  调用createEx 是继承而来的函数

8CFrameWnd::PreCreateWindow  PreCreateWindow是个虚函数,会调用子类的PreCreateWindow

 

在函数中有ex的,表示扩展函数。

 

 

创建窗口:

Create函数【WINFRM.cpp

调用CreateEx函数;【WINCORE.cpp中】

 

显示窗口:

CTestApp类成员函数InitInstance中;

代码实例:

     m_pMainWnd->ShowWindow(SW_SHOW);

     m_pMainWnd->UpdateWindow();

 

           数据成员m_pMainWnd是一个指针,保存了应用程序框架窗口的一个指针;

 

 

 

 

3MFC程序框架之四消息循环【参考资料:孙鑫VC++教学视频】

 

 

我们来研究MFC程序里面的消息循环:

CWinThread::Run函数里完成消息循环;

      里面有CWinThread::PumpMessage()   消息循环

      里面有  if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))

 

 

CMainFrame CTestView都是窗口类。 

CTestApp是应用程序类。有且只有一个应用程序类。

CTestDoc 继承于CDocument :是文档类。数据的存储加载。

数据的处理显示都是由CTestView类来实现。

CAboutDlg 是可有可无的,是专门帮助之类的功能。是从CWnd继承下来的。

 

3MFC程序框架之五补充【参考资料:孙鑫VC++教学视频】

 

当我们在查阅msdnvc的帮助时),会出现很多个结果,其中一个就是:

Windows User InterfacePlatform SDK

这个其实就是win32 API函数的意思;

 

模拟CWnd

class CWnd

{

public:

         BOOL CreateEx(DWORD dwExStyle,      // extended window style

                                     LPCTSTR lpClassName,    // registered class name

                                     LPCTSTR lpWindowName, // window name

                                     DWORD dwStyle,        // window style

                                     int x,                // horizontal position of window

                                     int y,                // vertical position of window

                                     int nWidth,           // window width

                                     int nHeight,          // window height

                                     HWND hWndParent,      // handle to parent or owner window

                                     HMENU hMenu,          // menu handle or child identifier

                                     HINSTANCE hInstance,  // handle to application instance

                                     LPVOID lpParam);        // window-creation data

         BOOL ShowWindow(int nCmdShow);

         BOOL UpdateWindow();

public:

         HWND m_hWnd;

};

 

BOOL CWnd::CreateEx(DWORD dwExStyle,      // extended window style

                                     LPCTSTR lpClassName,  // registered class name

                                     LPCTSTR lpWindowName, // window name

                                     DWORD dwStyle,        // window style

                                     int x,                // horizontal position of window

                                     int y,                // vertical position of window

                                     int nWidth,           // window width

                                     int nHeight,          // window height

                                     HWND hWndParent,      // handle to parent or owner window

                                     HMENU hMenu,          // menu handle or child identifier

                                     HINSTANCE hInstance,  // handle to application instance

                                     LPVOID lpParam)        // window-creation data

{

         m_hWnd=::CreateWindowEx(dwExStyle,lpClassName,dwStyle,x,y,

                                               nWidth,nHeight,hWndParent,hMenu,hInstance,

                                               lpParam);

         if(m_hWnd!=NULL)

                   return TRUE;      //因为是BOOL

         else

                   return FALSE;

}

 

BOOL CWnd::ShowWindow(int nCmdShow)

{

         return ::ShowWindow(m_hWnd,nCmdShow);

//为了区分,平台函数,和类函数一样的时候。所以加两个冒号。

//表示所使用的,是全局函数::之前不要加任何东西。

}

 

BOOL CWnd::UpdateWindow()

{

         return ::UpdateWindow(m_hWnd);

//为了区分,平台函数,和类函数一样的时候。所以加两个冒号。

//表示所使用的,是全局函数::之前不要加任何东西。

}

 

int WINAPI WinMain(

         HINSTANCE hInstance,      // handle to current instance

         HINSTANCE hPrevInstance,  // handle to previous instance

         LPSTR lpCmdLine,          // command line

         int nCmdShow              // show state

)

{

         WNDCLASS wndcls;  //int a;定义

         wndcls.cbClsExtra=0;

         wndcls.cbWndExtra=0;

         ......

         RegisterClass(&wndcls);  //注册

 

         CWnd wnd;   类,wnd不是窗口,是对象,如果关闭窗口,但是不会销毁对象。要看C++对象的生命周期。

         wnd.CreateEx(...);

         wnd.ShowWindow(SW_SHOWNORMAL);

         wnd.UpdateWindow();

 

//…..和上面的比较。。以前是如下写的,现在要像上面那样写。

         HWND hwnd;

         hwnd=CreateWindowEx();

         ::ShowWindow(hwnd,SW_SHOWNORMAL);

         ::UpdateWindow(hwnd);

 

         ......

}

 

 

如果平台SDK函数为了和类的成员函数区分(主要是两个函数名字是一样的),我们是这样表示的:

::ShowWindow(…)

这样表示这个ShowWindow是平台SDK函数,Win32API函数,是一个全局函数;

还有return ::UpdateWindow(m_hWnd); 也是同样的道理;

 

 

  CWnd wnd;类对象是窗口吗?不是

int WINAPI WinMain(

  HINSTANCE hInstance,      // handle to current instance

  HINSTANCE hPrevInstance,  // handle to previous instance

  LPSTR lpCmdLine,          // command line

  int nCmdShow              // show state

)

{

       WNDCLASS wndcls;

       wndcls.cbClsExtra=0;

       wndcls.cbWndExtra=0;

       ......

       RegisterClass(&wndcls);

 

       CWnd wnd; 

       wnd.CreateEx(...);

       wnd.ShowWindow(SW_SHOWNORMAL);

       wnd.UpdateWindow();

 

       HWND hwnd;

       hwnd=CreateWindowEx();

       ::ShowWindow(hwnd,SW_SHOWNORMAL);

       ::UpdateWindow(hwnd);

 

       ......

}

蓝色的语句中CWnd wnd表示一个类对象;红色的语句中HWND hwnd表示一个对话框的句柄;

 

如果是同一个东西的话,他们的消亡应该是同时的,但是实际上并不是同时的。类对象的释放后,窗口句柄依然可以存在,除非人为同时释放;

 

所以CWnd类对象和窗口不是同一个东西;

  

3MFC程序框架之六创建按钮【参考资料:孙鑫VC++教学视频】

 

直接实践:

第一步:框架函数创建后,才能创建button函数。

CMainFrame类里面,增加一个数据成员,CButton m_btn; 私有的;在最前面。

第二步:wm=window message

WM_CREATE这个消息响应函数里面,创建按钮:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

//位置在这个响应函数的最后

m_btn.Create("维新",WS_CHILD | BS_DEFPUSHBUTTON,  CRect (0,0,100,100),

this,123);  //123是编号。     //设定this 即 CmainFrame为父窗口!

m_btn.ShowWindow(SW_SHOWNORMAL);

return 0;

}

 

m_****    变量名,表示类的成员变量。

 

如果我们修改m_btn.Create函数:

m_btn.Create("维新",WS_CHILD|WS_VISIBLE | BS_DEFPUSHBUTTON,CRect(0,0,100,100),this,123);

m_btn.ShowWindow(…); 可以不要;WS_VISIBLE 是可视化的意思

 

按钮出现在客户区域,在菜单的下面;此时是在CMainFrame里的。

 

下面我们用同样的方法,在view类里面做同样的事情,没有OnCreate函数,但是OnCreate函数要自己增加,使用增加消息处理器message handlers;

同样的步骤。。。。。。

此时的按钮是在view里显示。

 

接下去,要讨论一下框架类的指针如何获得(也就是不用this),直接使用框架类的指针?

框架类是View类的一个父窗口;

CWnd::GetParent()函数来实现;

m_btn.Create("维新",WS_CHILD | WS_VISIBLE | BS_AUTO3STATE,CRect(0,0,100,100),GetParent(),123);

 

★按钮的位置和代码所放的位置无关,和父窗口的指针有关;

你可能感兴趣的:(MFC,MFC)