转载地址:https://blog.csdn.net/u012377333/article/details/40789893
孙鑫视频02是介绍C++,这部分不说了,03是介绍MFC,真是深入浅出,所以第一章要好好理解,第三章可以一步步查找创建窗口的4个过程。
有了一定的Windows32编程知识,就能学习MFC了。
在学习MFC之前,一定要弄明白Windows32编程中的消息循环是怎么回事。MFC实际上就是对Windows API函数的封装。
在Windows程序设计编程中,创建一个窗口要经历下面四个过程 (如有不懂,请看博客 win32初窥)
-
#include<iostream> -
#include<string> -
using namespace std; -
-
class Person -
{ -
public: -
Person *p; -
Person() -
{ -
p=this;//保存this指针 -
} -
virtual void say() -
{ -
cout<<“Person’s say()”<<endl; -
} -
-
}; -
-
class Student:public Person -
{ -
public: -
-
Student() -
{ -
-
} -
void say() -
{ -
cout<<“Student’s say()”<<endl; -
} -
-
}; -
-
Student s; -
-
int main() -
{ -
-
s.p->say();//这里将调用子类的方法 -
return 0; -
}
其中CMainFrame表示一个窗口(主窗体,包括标题栏,菜单…),XXApp表示运用程序,XXDOC表示文档类(加载数据,实现数据的存储与操作分离),XXView也表示一个窗口(相当于Windows的客户区)
下面看看MFC中类的主要继承关系:
由于继承树太大,这里只罗列了CWnd的继承关系
API中CreateWindowEx和CreateWindow几乎是一样的,Ex表示扩展,多了一个参数
下面用API模拟CWnd
just模拟
-
//下面是模仿封装API函数 -
-
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,lClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent, -
hMenu,hInstance,lParam); -
-
if(m_hWnd!=NULL) -
-
return TRUE; -
else -
return FALSE; -
} -
-
BOOL CWnd::ShowWindow(int nCmdShow) -
{ -
return ::ShowWindow(m_hWnd,nCmdShow);//调用的是SDK全局函数,加个::说明是全局的 -
} -
-
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 wndclass; -
-
wndclass.cbClsExtra=0; -
wndclass.cbWndExtra=0; -
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); -
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); -
wndclass.hIcon=LoadIcon(NULL,IDI_ERROR); -
wndclass.hInstance=hInstance; -
… -
-
CWnd cwnd; -
cwnd.CreateEx(dwExstyle,…,…); -
-
cwnd.ShowWindow(nCmdShow); -
cwnd.UpdateWindow(); -
-
while(GetMessage(&msg,NULL,0,0)) -
{ -
TranslateMessage(&msg); -
DispatchMessage(&msg); -
} -
-
… -
}
下面是重头戏(引用了某位仁兄的,太详细了)
重点:MFC运行机制
提示:对于不想理解内部运行过程的,可以不看这一章,可以看了后面的界面设计再回头来看这一章,可能感觉更深刻。
这一次课和上一次的课的重点就是MFC的窗口类创建过程,而要反复说明的就是:MFC的程序和C语言的程序,从执行原理上说,是完全一致的。
抓住这一点,那么对于理解MFC程序的运行机制也就相对于简单了。
C中的main函数就相当于MFC中的WinMain函数。
感兴趣的可以利用VC的断点设置自己跟踪下面讲述的各个函数,就明白它的执行顺序了。
一、C语言程序执行步骤
在C语言中,大约的步骤如下:
1, 全局变量内存分配
2, 进入main函数
二、MFC程序的运行步骤(主要是初始化)
打开一个MFC APPWizard(exe)工程,跟踪其执行步骤,可以发现,是以下顺序:
1) CXXApp中的全局变量定义
CXXApp theApp;
2) 调用CXXApp构造函数
CXXApp ::CXXApp(){}
3) 进入Winmain函数(_tWinMain为宏,值为WinMain)
_tWinMain(){}
4) 完成初始化工作:包括窗口类注册、窗口产生、显示和更新
pThread->InitInstance()
对于MFC程序,MainFrame,View,ToolBar,Controlbar等都是窗口,所以下面的窗口注册与创建、显示等要反复调用多次,一次对应一个窗口
(1) 注册窗口类
AfxEndDeferRegisterClass
(2) 创建窗口
CMainFrame::PreCreateWindow()//反复调用一次是给我们修改窗口属性的机会
CFrameWnd::Create()
(3) 消息循环
PumpMessage()
补充1:
在MFC中,由于涉及到(窗口)类定义,所以定义全局变量的时候,需要进行更多的步骤。
全局变量涉及到类定义(类似于C中的类型定义)的话,那么需要遵循以下步骤(以MFC的窗口类为例)
1) 设计一个窗口类
2) 注册窗口类
3) 创建窗口
4) 显示及更新窗口
5) 消息循环
补充2:其他需要注意的几点
1, 每一个MFC程序,有且只有一个从WinApp类派生的类(应用程序类),也只有一个从应用程序类所事例化的对象,表示应用程序本身。在WIN32程序当中,表示应用程序是通过WINMAIN入口函数来表示的(通过一个应用程序的一个事例号这一个标识来表示的)。在基于MFC应用程序中,是通过产生一个应用程序对象,用它来唯一的表示了应用程序。
2, _tWinMain函数中通过调用AfxWinMain()函数来完成它要完成的功能。(Afx*前缀代表这是应用程序框架函数,是一些全局函数,应用程序框架是一套辅助生成应用程序的框架模型,把一些类做一些有机的集成,我们可根据这些类函数来设计自己的应用程序)。
3, 设计窗口类:在MFC中事先设计好了几种缺省的窗口类,根据不同的应用程序的选择,调用AfxEndDeferRegisterClass()函数注册所选择的窗口类。
4, PreCreateWindow()是个虚函数,如果子类有则调用子类的。
5, CreateWindowEx()函数参数与CREATESTRUCT结构体成员完全一致,CreateWindowEx()函数与CREATESTRUCT结构体参数的对应关系,使我们在创建窗口之前通过可PreCreateWindow(cs)修改cs结构体成员来修改所要的窗口外观。
6,注意两个函数。
::TranslateMessage(&m_msgCur)函数进行消息(如键盘消息)转换
::DispatchMessage(&m_msgCur)函数分派消息到窗口的回调函数处理(实际上分派的消息经过消息映射,交由消息响应函数进行处理。)
7,可以认为View类窗口是CMainFram类窗口的子窗口。DOCument类是文档类。DOC-VIEW结构将数据本身与它的显示分离开。
文档类用于数据的存储,加载;视类用于数据的显示,修改
8,CTEApp::InitInstance()函数中通过文档模板将文档类,视类,框架类的有机组织一起。语句如下:
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTEDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CTEView));
AddDocTemplate(pDocTemplate);//增加到模板
补充3:本课涉及到MFC函数的源文件位置
根目录
找到您安装VC98下MFC的位置,比如我的机子上为:D:\Program Files\Microsoft Visual Studio\VC98\MFC。下面提供的就是相对路径了。
CWinApp构造函数: MFC=>SRC=>APPCORE.CPP
AfxWinMain:MFC=>SRC=>WINMAIN.CPP
AfxEndDeferRegisterClass: MFC=>SRC=>APPCORE.CPP
CFrameWnd::PreCreateWindow()函数所在文件:MFC=>SRC=>WINFRM.CPP
CFrameWnd::Create()函数路径:MFC=>SRC=>WINFRM.CPP
CWnd::CreateEx()函数路径:MFC=>SRC=>WINCORE.CPP
CWinThread::Run()方法路径:MFC=>SRC=>THRDCORE.CPP
创建按钮
1在CMainFrame创建
双击CMainFrame,添加数据成员,CButton m_btn
在OnCreate方法添加如下代码:
-
m_btn.Create(TEXT(“first Button”),BS_PUSHBUTTON|WS_CHILD,CRect(0,0,100,100),this,123); -
m_btn.ShowWindow(SW_NORMAL);
2在CXXView创建
双击CXXView,添加数据成员,CButton m_btn
在CXXView右键Add windows Message Handler 添加WM_CREATE消息处理,然后生成OnCreate函数
在OnCreate函数添加如下代码
-
m_btn.Create(TEXT(“Button2”),BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE,CRect(0,0,100,100),this,123);
两个代码效果是等价的:
</div>
</div>
</article>
有了一定的Windows32编程知识,就能学习MFC了。
在学习MFC之前,一定要弄明白Windows32编程中的消息循环是怎么回事。MFC实际上就是对Windows API函数的封装。
在Windows程序设计编程中,创建一个窗口要经历下面四个过程 (如有不懂,请看博客 win32初窥)
-
#include<iostream> -
#include<string> -
using namespace std; -
-
class Person -
{ -
public: -
Person *p; -
Person() -
{ -
p=this;//保存this指针 -
} -
virtual void say() -
{ -
cout<<“Person’s say()”<<endl; -
} -
-
}; -
-
class Student:public Person -
{ -
public: -
-
Student() -
{ -
-
} -
void say() -
{ -
cout<<“Student’s say()”<<endl; -
} -
-
}; -
-
Student s; -
-
int main() -
{ -
-
s.p->say();//这里将调用子类的方法 -
return 0; -
}
其中CMainFrame表示一个窗口(主窗体,包括标题栏,菜单…),XXApp表示运用程序,XXDOC表示文档类(加载数据,实现数据的存储与操作分离),XXView也表示一个窗口(相当于Windows的客户区)
下面看看MFC中类的主要继承关系:
由于继承树太大,这里只罗列了CWnd的继承关系
API中CreateWindowEx和CreateWindow几乎是一样的,Ex表示扩展,多了一个参数
下面用API模拟CWnd
just模拟
-
//下面是模仿封装API函数 -
-
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,lClassName,lpWindowName,dwStyle,x,y,nWidth,nHeight,hWndParent, -
hMenu,hInstance,lParam); -
-
if(m_hWnd!=NULL) -
-
return TRUE; -
else -
return FALSE; -
} -
-
BOOL CWnd::ShowWindow(int nCmdShow) -
{ -
return ::ShowWindow(m_hWnd,nCmdShow);//调用的是SDK全局函数,加个::说明是全局的 -
} -
-
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 wndclass; -
-
wndclass.cbClsExtra=0; -
wndclass.cbWndExtra=0; -
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); -
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); -
wndclass.hIcon=LoadIcon(NULL,IDI_ERROR); -
wndclass.hInstance=hInstance; -
… -
-
CWnd cwnd; -
cwnd.CreateEx(dwExstyle,…,…); -
-
cwnd.ShowWindow(nCmdShow); -
cwnd.UpdateWindow(); -
-
while(GetMessage(&msg,NULL,0,0)) -
{ -
TranslateMessage(&msg); -
DispatchMessage(&msg); -
} -
-
… -
}
下面是重头戏(引用了某位仁兄的,太详细了)
重点:MFC运行机制
提示:对于不想理解内部运行过程的,可以不看这一章,可以看了后面的界面设计再回头来看这一章,可能感觉更深刻。
这一次课和上一次的课的重点就是MFC的窗口类创建过程,而要反复说明的就是:MFC的程序和C语言的程序,从执行原理上说,是完全一致的。
抓住这一点,那么对于理解MFC程序的运行机制也就相对于简单了。
C中的main函数就相当于MFC中的WinMain函数。
感兴趣的可以利用VC的断点设置自己跟踪下面讲述的各个函数,就明白它的执行顺序了。
一、C语言程序执行步骤
在C语言中,大约的步骤如下:
1, 全局变量内存分配
2, 进入main函数
二、MFC程序的运行步骤(主要是初始化)
打开一个MFC APPWizard(exe)工程,跟踪其执行步骤,可以发现,是以下顺序:
1) CXXApp中的全局变量定义
CXXApp theApp;
2) 调用CXXApp构造函数
CXXApp ::CXXApp(){}
3) 进入Winmain函数(_tWinMain为宏,值为WinMain)
_tWinMain(){}
4) 完成初始化工作:包括窗口类注册、窗口产生、显示和更新
pThread->InitInstance()
对于MFC程序,MainFrame,View,ToolBar,Controlbar等都是窗口,所以下面的窗口注册与创建、显示等要反复调用多次,一次对应一个窗口
(1) 注册窗口类
AfxEndDeferRegisterClass
(2) 创建窗口
CMainFrame::PreCreateWindow()//反复调用一次是给我们修改窗口属性的机会
CFrameWnd::Create()
(3) 消息循环
PumpMessage()
补充1:
在MFC中,由于涉及到(窗口)类定义,所以定义全局变量的时候,需要进行更多的步骤。
全局变量涉及到类定义(类似于C中的类型定义)的话,那么需要遵循以下步骤(以MFC的窗口类为例)
1) 设计一个窗口类
2) 注册窗口类
3) 创建窗口
4) 显示及更新窗口
5) 消息循环
补充2:其他需要注意的几点
1, 每一个MFC程序,有且只有一个从WinApp类派生的类(应用程序类),也只有一个从应用程序类所事例化的对象,表示应用程序本身。在WIN32程序当中,表示应用程序是通过WINMAIN入口函数来表示的(通过一个应用程序的一个事例号这一个标识来表示的)。在基于MFC应用程序中,是通过产生一个应用程序对象,用它来唯一的表示了应用程序。
2, _tWinMain函数中通过调用AfxWinMain()函数来完成它要完成的功能。(Afx*前缀代表这是应用程序框架函数,是一些全局函数,应用程序框架是一套辅助生成应用程序的框架模型,把一些类做一些有机的集成,我们可根据这些类函数来设计自己的应用程序)。
3, 设计窗口类:在MFC中事先设计好了几种缺省的窗口类,根据不同的应用程序的选择,调用AfxEndDeferRegisterClass()函数注册所选择的窗口类。
4, PreCreateWindow()是个虚函数,如果子类有则调用子类的。
5, CreateWindowEx()函数参数与CREATESTRUCT结构体成员完全一致,CreateWindowEx()函数与CREATESTRUCT结构体参数的对应关系,使我们在创建窗口之前通过可PreCreateWindow(cs)修改cs结构体成员来修改所要的窗口外观。
6,注意两个函数。
::TranslateMessage(&m_msgCur)函数进行消息(如键盘消息)转换
::DispatchMessage(&m_msgCur)函数分派消息到窗口的回调函数处理(实际上分派的消息经过消息映射,交由消息响应函数进行处理。)
7,可以认为View类窗口是CMainFram类窗口的子窗口。DOCument类是文档类。DOC-VIEW结构将数据本身与它的显示分离开。
文档类用于数据的存储,加载;视类用于数据的显示,修改
8,CTEApp::InitInstance()函数中通过文档模板将文档类,视类,框架类的有机组织一起。语句如下:
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTEDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CTEView));
AddDocTemplate(pDocTemplate);//增加到模板
补充3:本课涉及到MFC函数的源文件位置
根目录
找到您安装VC98下MFC的位置,比如我的机子上为:D:\Program Files\Microsoft Visual Studio\VC98\MFC。下面提供的就是相对路径了。
CWinApp构造函数: MFC=>SRC=>APPCORE.CPP
AfxWinMain:MFC=>SRC=>WINMAIN.CPP
AfxEndDeferRegisterClass: MFC=>SRC=>APPCORE.CPP
CFrameWnd::PreCreateWindow()函数所在文件:MFC=>SRC=>WINFRM.CPP
CFrameWnd::Create()函数路径:MFC=>SRC=>WINFRM.CPP
CWnd::CreateEx()函数路径:MFC=>SRC=>WINCORE.CPP
CWinThread::Run()方法路径:MFC=>SRC=>THRDCORE.CPP
创建按钮
1在CMainFrame创建
双击CMainFrame,添加数据成员,CButton m_btn
在OnCreate方法添加如下代码:
-
m_btn.Create(TEXT(“first Button”),BS_PUSHBUTTON|WS_CHILD,CRect(0,0,100,100),this,123); -
m_btn.ShowWindow(SW_NORMAL);
2在CXXView创建
双击CXXView,添加数据成员,CButton m_btn
在CXXView右键Add windows Message Handler 添加WM_CREATE消息处理,然后生成OnCreate函数
在OnCreate函数添加如下代码
-
m_btn.Create(TEXT(“Button2”),BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE,CRect(0,0,100,100),this,123);
两个代码效果是等价的:
</div>
</div>
</article>