◇MFC库的类表记录在Hierarchy Chart中
◇得到父类的指针用GetParent()。
◇CWND封装了一些关于窗口操作的类,CWinAPP这个类是应用程序的类。
◇在安装目录下的VC98/MFC/SRC,这个目录下面就是MFC的原代码,WinMain函数的所在地方就是APPMODUL.CPP
◇AfxWinMain函数:以Afx开头的函数属于应用程序框架的函数,在这个函数里面,有相应获取的代码。其中AfxGetApp是一个全局的函数,也一方面说明了C++不是完全面向对象的。
◇CTheApp theApp;->CTestApp ::CTestApp(){}->_tWinMain(){}启动调用顺序。
CwindThread* pThread = AfxGetThread();
//pThread与pApp等价的,它完成窗口初始化工作,完成窗口的注册,完成窗口的创建,显示和更新。
CwinApp* pApp = AfxGetApp();
//初始化子类的函数,在父类中他是个虚函数
pThread-》InitInstance();
pThread-》Run();
AfxGetApp()获取一个指向CWinApp派生类对象(theApp)的指针。
pApp调用三个函数,这三个函数完成设计窗口类、注册窗口类、创建窗口、显示窗口、更新窗口、消息循环、消息处理函数。
◇ 注册窗口:AfxEndDeferRegisterClass,在运行的时候注册,其实单文档的程序是比较例外的,一般都是在创建窗口之前注册窗口。
CframeWnd::PreCreateWindow(){
//再这里调用AfxEndDeferRegisterClass
}
◇
然后是创建窗口:创建窗口时的函数调用关系:
Create() -> CreateEx() -> PreCreateWindow() -> AfxEndDeferRegisterClass()
Create()函数由谁调用?是由LoadFrame()调用。
BOOL CWnd::CreateEx(...){
...
if (!PreCreateWindow(cs))//虚函数,如果子类有调用子类的。
{
PostNcDestroy();
return FALSE;
}
...
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
...
}
◇
HWND CreateWindowEx(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
typedef struct tagCREATESTRUCT { // cs
LPVOID lpCreateParams;
HINSTANCE hInstance;
HMENU hMenu;
HWND hwndParent;
int cy;
int cx;
int y;
int x;
LONG style;
LPCTSTR lpszName;
LPCTSTR lpszClass;
DWORD dwExStyle;
} CREATESTRUCT;
◇ CreateWindowEx()函数与CREATESTRUCT结构体参数的对应关系,使我们在创建窗口之前通过可PreCreateWindow(cs)修改CREATESTRUCT cs结构体成员来修改所要的窗口外观。
显示和更新窗口:
CTestApp类,TestApp.cpp中
// m_pMainWnd保存了框架窗口对象的指针
m_pMainWnd->ShowWindow(SW_SHOW);//显示窗口,m_pMainWnd指向框架窗口
m_pMainWnd->UpdateWindow();//更新窗口
◇
消息循环:由pThread->Run();完成。
int AFXAPI AfxWinMain()
{ ...
if (!pThread->InitInstance()){...}
//完成窗口初始化工作,完成窗口的注册,完成窗口的创建,显示和更新。
nReturnCode = pThread->Run();
//继承基类Run()方法,调用CWinThread::Run()来完成消息循环
...
}
◇
CWinThread::Run()方法路径:MFC|SRC|THRDCORE.CPP
int CWinThread::Run()
{ ...
// phase2: pump messages while available
do//消息循环
{
// pump message, but quit on WM_QUIT
if (!PumpMessage())//取消息并处理
return ExitInstance();
...
} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
...
}然后始终都是在这个消息循环的内部进行了
◇ 流程:全局对象的初始化,然后进入到WinMain函数,然后获取子类的指针,利用子类的指针我们去调用一个虚拟的函数(InitInstance),其中里面要做注册窗口,创建窗口,创建之前也要设置窗口的各个属性,然后启动窗口
◇
BOOL CWinThread::PumpMessage()
{
...
if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))//取消息
{...}
...
// process this message
if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur))
{
::TranslateMessage(&m_msgCur);//进行消息(如键盘消息)转换
::DispatchMessage(&m_msgCur);//分派消息到窗口的回调函数处理(实际上分派的消息经过消息映射,交由消息响应函数进行处理。)
}
return TRUE;
}
◇
文档类,视类,框架类的有机结合:
在CTestApp类CTestApp::InitInstance()函数中通过文档模板将文档类,视类,框架类的有机组织一起。CsingleDocTemplate就是单文档的类
...
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTEDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CTEView));
AddDocTemplate(pDocTemplate);//增加到模板
◇ 仿真窗口类的代码清单:
class CWnd{
public:
BOOL CreateEx(
DWORD dwExstyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x ,
int y
int nWidth,
int nHeight,
HWND hWndParent,
HMWNU hMenu,
HINSTANCE hInstance,
LPVOID lpParam );
BOOL ShowWindow(int nCmdShow);
BOOL UpdateWindow();
public:
HWND m_hwnd; //m_hwnd在构造函数中将其初始化为NULL
};
BOOL CWnd::CreateEx(
DWORD dwExstyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x ,
int y
int nWidth,
int nHeight,
HWND hWndParent,
HMWNU hMenu,
HINSTANCE hInstance,
LPVOID lpParam );
{
m_hWnd = ::CreateWindowEx(dwExstyle, lpClassName, dwStyle,
x, y, nWidth,nHeight, hWndParent, hMenu, hInstance, lpParam);
if(m_hWnd != NULL )
return TRUE;
else
return FALSE;
}//END CreateEx()
BOOL CWnd::ShowWindow (int nCmdShow)
{
::ShowWindow (m_hWnd,nCmdShow); //在函数前面加上的含义表示使用的是全局函数,
//以前使用全局函数的时候可以直接写函数名就行了,现在加上“ :: ”是为了防止与 windows API 函数混淆
}
BOOL CWnd :: UpdateWindow()
{
//::代表的是全局的函数
::UpdateWindow ( m_hWnd);
}
nt WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdshow)
{
//设计窗口类
WNDCLASS wndcls;
wndcls.cbClsExtra = 0;
wndcls.cbWndExtra = 0;
.................
//注册窗口类
RegisterClass (& wndcls);
CWnd wnd; //wnd并不等价于窗口,当窗口销毁之后,C++对象还可以存在,他是连接窗口的纽带
wnd.CreateEx(dwExstyle, lpClassName, dwStyle,
x, y, nWidth,nHeight, hWndParent, hMenu, hInstance, lpParam);
wnd.ShowWindow(SW_SHOWNUORMAL); //注意这里不再需要传递hwnd句柄,因为wnd里面已经定义了句柄 m_hwnd
wnd.UpdateWindow();
}//endof WinMain()
◇ Button控件的产生:窗口创建之后创建Button,其中RECT是矩形区域,可以设定Button的大小。Cbutton在执行西构以后,会将Button的控件资源进行回收。MFC的类维护了窗口,一般的MFC类在析构函数中都会销毁窗口。所以,当MFC的类生命周期到的时候,窗口的生命周期就到了。但是,反过来,当窗口的生命周期到的时候,相应的类的生命周期就不一定了,类还是可以使用的。
◇ CButton m_btn;
int CTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
。。。。
m_btn.Create("维新",WS_CHILD | WS_VISIBLE | BS_AUTO3STATE,
CRect(0,0,100,100),/*GetParent(),*/this,123);
//m_btn.ShowWindow(SW_SHOWNORMAL);
}