1.MFC中的默认类
1.1 CObject类是MFC提供的绝大多数类的基类,它本身并不提供什么功能,主要是通过6个宏完成实际工作。主要完成动态空间的分配与回收,支持一般的诊断、出错信息处理和文档序列化等。动态类型创建和识别都是在这里进行处理。
1.2 CCmdTarget类由CObject类直接派生,它是MFC消息映射结构的基类,消息映射将系统事件(命令)和窗口事件(消息)发送给响应这些事件的对象,完成消息发送、等待和调度工作,实现应用程序对象之间的协调运行。—这里,命令是指来自菜单项、命令按钮和加速键的消息。
1.3 CWinThread类主要用来完成对线程的控制,包括线程的创建、运行、终止和挂起等。
1.4 CWinApp类是应用程序的管理者,MFC中一个全局的对象,tWinMain执行之前会先构造该对象。管理程序的生死,操纵每个对象的产生。(关键的函数:InitApplication/InitInstance)(应用类)类封装了Windows应用的初始化、运行以及终止的全过程。CWinApp本身就代表一个程序本体,程序本体是指与程序本身有关而不与窗口有关的数据或动作。比如,WinMain传递的四个参数,注册窗口类,分派消息等。比如,CWinApp类中就定义了WinMain函数的四个参数(m_hInstance,m_hPrevInstance,m_lpCmdLine,m_nCmdShow)。还定义了一些重要的如 InitApplication(),InitInstance(),Run()等函数。传统的WinMain函数就是由此三个函数完成。另外,CWinApp中还应该有个主窗口的handle,是的,但它不在CWinApp类中,而是在CWinThread类中实现,在CWinThread类中,有一个指向窗口类的指针的成员变量。如下所示 CWnd* m_pMainWnd
对于每一个基于框架应用,它必须且只能有一个派生于CWinApp的类对象。这个对象的特别之处在于它是一个全局对象,因此它在创建任何窗口前首先被构造。类CWinApp提供了几个关键的可重载的虚成员函数,它们是InitInstance、Run、ExitInstance以及OnIdle等。而且在程序中可以随时调用全局函数AfxGetApp,以便获得CWinApp类对象的指针。
1.5 CWnd类提供了微软基础类库中所有窗口类的基本功能。CWnd对象与Windows的窗口不同,但是两者有紧密联系。CWnd对象是由CWnd的构造函数和析构函数创建或销毁的。另一方面,Windows的窗口是Windows的一种内部数据结构,它是由CWnd的Create成员函数创建的,而由CWnd的虚拟析构函数销毁。DestroyWindow函数销毁Windows的窗口,但是不销毁对象。CWnd类和消息映射机制隐藏了WndProc函数。接收到的Windows通知消息通过消息映射被自动发送到适当的CWnd OnWndMsg成员函数。你可以在派生类中重载OnWndMsg成员函数以处理成员的特定消息。CWnd类同时还使你能够为应用程序创建Windows的子窗口。先从CWnd继承一个类,然后在派生类中加入成员变量以保存与你的应用程序有关的数据。在派生类中实现消息处理成员函数和消息映射,以指定当消息被发送到窗口时应该如何动作。
1.6 CFrameWnd类往往用于创建应用程序的主窗口,因为它能很好地支持系统菜单和控制条(工具条、状态条等),为此定义了大量的成员函数和变量。在编写文档/视图结构的应用程序时,CFrameWnd作为主窗口管理视图和文档对象。视图对象和控制条都成为CFrameWnd的子窗口,它们分享客户区,其位置被CFrameWnd有效地排列。CFrameWnd直接支持单文档界面(SDI),对于多文档界面(MDI),使用其派生类CMDIFrameWnd和CMDIChildWnd。
1.7 CView视图类的主要功能是显示文档数据,并接受用户对数据的修改。它以图形化方式将数据显示出来,并提供了与用户交互的接口,将用户的输入操作解释为对文档对象的操作。一个视图对象只能与一个文档对象连接,视图类是文档与用户间进行联系的纽带,当用户打开一个窗口或分割一个窗口时,程序框架就会构造一个视图类对象与文档相关联,一个文档对象可连接多个视图对象。当文档对象发生变化时,与该文档连接的所有视图都应做出反应,这一过程通过调用CDocument::UpdateAllViews()函数来得到实现。CView成员不太多,同CDocument类似,它也只提供了基础、必要的框架,用户通过对该类的派生来充实所需的功能。
1.8 CDialog类是在屏幕上显示的对话框基类。对话框有两类:模态对话框和非模态对话框。模态对话框在应用继续进行之前必须关闭。非模态对话框允许用户执行另外的操作而不必取消或删除该对话框。
2.创建好一个MFC项目后自带的四个类
2.1 CWinApp:应用程序管理者,代表应用程序;
包含InitApplication(),InitInstance(),Run()等函数;
包含主函数的四个参数(m_hInstance,m_hPrevInstance,m_lpCmdLine,m_nCmdShow);
包含主窗口的指针 CWnd*m_pMainWnd ,单文档程序指向CFrameWnd,对话框的程序指向CDialog。
2.2 CFrameWnd:通常做为主窗口;
用来管理CDocument,CView,它们分享客户区;
标题栏,菜单栏分享非客户区。
2.3 CView:显示文档数据;
通常用来绘图。
2.4 CDocument:保存数据。
3.自定义消息
3.1 我们考虑在 View 上点击鼠标左键给 Frame 发送一个自定义消息该如何实现?
1.首先考虑什么时候:按下鼠标左键的时候;做什么事:给 Frame 发送自定义消息;
2.我们是给 View 类添加标准鼠标按键消息,因此选择 类视图 ,View类上右键,选择 属性,添加 OnLButtonDown 函数;
3.在该函数中完成 发送自定义消息 的操作;
4.要发送自定义消息,首先得有自定义消息,因此我们在 stdafx.h 里添加一行: #define UM_VIEW_TO_FRAME (WM_USER+1);
5.在 OnLButtonDown 中添加: ::(AfxGetMainWnd()->h_Wnd, UM_VIEW_TO_FRAME, 0, 0);
6.之后我们需要在 Frame 类里添加消息映射表:ON_MESSAGE(UM_VIEW_TO_FRAME, &CMainFrame::OnViewToFrame),因此我们还需要添加一个:afx_msg LRESULT OnViewToFrame(WPARAM wParam, LPARAM lParam) 函数来对 UM_VIEW_TO_FRAME 消息进行处理,在 OnViewToFrame 函数中,我们使用 TRACE 来输出一行文字:TRACE(“CMainFrame::OnViewToFrame\n”);
7.此时点击 View 视图框就会看到一行 CMainFrame::OnViewToFrame 的输出,程序运行正确。
PS. 1.在上述过程中,首先我们来解释一下为什么自定义消息时定义的数字为 WM_USER+1 ,因为我们无法确定哪些是系统已经使用了的,因此我们从 WM_USER 开始定义自己的消息数字就可以避免重复;
PS. 2.关于 SendMessage 函数,其需要的第一个参数是接受消息的窗口句柄,本次接收消息的窗口句柄是 Frame 的句柄,即主窗口的句柄,而主窗口的句柄包含在 CMainFrame 里,因此我们先获取 MainWnd ,再从中取得 m_hWnd 句柄;
PS. 3.SendMessage 与 PostMessage 的区别:SendMessage 是立即处理,直接调用回调函数,而 PostMessage 则是发送完消息直接执行下一行语句;
PS. 4.关于 Frame 类中的处理 UM_VIEW_TO_FRAME 消息的函数,我们是从 ON_MESSAGE 宏的定义中得知我们需要创建一个返回值为 LRESULT 、参数为 (WPARAM, LPARAM) 的函数的;
PS. 5.我们还可以使用 m_hWnd 句柄来调用函数: AfxGetMainWnd()->SendMessage(UM_VIEW_TO_FRAME) 来进行消息的发送。
3.2 我们考虑在标题栏上点击鼠标后给 View 发送一个消息
1.首先确定什么时候:点击标题栏;做什么事:给 View 发送消息;
2.我们给 Frame 类添加一个 OnNcLButtonDown 消息,在该函数中从 Frame 给 View 发送消息,发送的消息我们仍然在 stdafx.h 中自定义:#define UM_FRAME_TO_VIEW (WM_USER+2);
3.我们想要向 View 发送消息,就需要获得 View 的句柄: GetActiveView()->SendMessage(UM_FRAME_TO_VIEW) ;
4.给 View 类添加 ON_MESSAGE 消息映射表, ON_MESSAGE(UM_FRAME_TO_VIEW, &CMy113MFCView::OnFrameToView) ;我们添加一个类似于 3.1 中的 OnViewToFrame 函数: afx_msg LRESULT OnFrameToView(WPARAM wParam, LPARAM lParam) ;在其中加入语句:TRACE(“OnFrameToView\n”);
5.完成以上即可运行成功。
3.3 我们考虑发送一个整型数据
1.规定为从 Frame 给 View 发送消息,因此与 3.2 基本相同,只有在发送消息处略有不同:首先我们定义一个整型变量 a ,int a = 100;其次我们使用:GetActiveView()->SendMessage(UM_FRAME_TO_VIEW, a) 来进行整型数据的发送;
2.在 View 的接收端,我们使用:TRACE(“传送的值为:%d\n”, wParam) 来进行接受值的输出,以此来验证传送数据是否正确;
3.完成上述步骤,我们即可完成由 Frame 向 View 传送一个整型数据。
3.4 我们考虑发送一个整形数组
1.规定为从 Frame 给 View 发送消息,因此与 3.2 基本相同,只有在发送消息处略有不同:首先我们定义一个整型数组 arr[5] ,int arr[5] = {1, 2, 3, 4, 5}; 其次我们使用:GetActiveView()->SendMessage(UM_FRAME_TO_VIEW, 5, (LPARAM)arr) 来进行发送数据,这里的第二个参数 5 是指我们将要传送五个数据(1, 2, 3, 4, 5这五个数),第三个参数的类型是 LPARAM ,因此需要将 arr 数组强制转换为 LPARAM 的类型来进行传送;
2.在 View 的接收端,我们首先定义一个 CString 类型的变量 str 来以 12345 的形式打印传过来的5个值,我们使用一个指针 pArr 来记录传送过来的数组的地址:int pArr = (int)lParam ;其次我们通过循环来记录传送的具体的值;最后我们对 str 进行输出以检测我们传送的数据是否正确;
3.具体程序:
LRESULT CMy113MFCView::OnFrameToView(WPARAM wParam, LPARAM lParam)
{
// 5.接受数组数据
CString str;
int *pArr = (int *)lParam;
for(unsigned int i=0; i<wParam; i++)
{
CString temp;
temp.Format(L"%d", pArr[i]); // 为了将int值变为 CString 类型的值
str += temp;
}
TRACE(str);
return 0;
}