MFC基本结构问题

时间:2009-12-24 12:28:25

标签: c++ windows multithreading mfc event-handling

我不确定的事情很少:

当您使用MFC应用程序向导(让我们称之为TestMfc)创建基本SDI时,您会得到:

4个主要班级:

CTestMfcApp
CTestMfcView
CTestMfcDoc
CMainFrame

我注意到CTestMfcApp有那些声明

ON_COMMAND(ID_APP_ABOUT, &CTestMfcApp::OnAppAbout)
    // Standard file based document commands
    ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew)
    ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)
    // Standard print setup command
    ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinApp::OnFilePrintSetup)

while CTestMfcView has those :
BEGIN_MESSAGE_MAP(CTestMfcView, CEditView)
    // Standard printing commands
    ON_COMMAND(ID_FILE_PRINT, &CEditView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_DIRECT, &CEditView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CEditView::OnFilePrintPreview)
END_MESSAGE_MAP()

我不明白为什么MFC会创造这种分离? 我不明白为什么app类需要声明处理事件的函数...这不是视图的工作吗?如果例如窗户很少,那就更加明显了。

其次,如何调用这些事件?我知道应该有WINPROC函数谁应该得到MSG并调用正确的处理程序。 ON_COMMAND是设置某种指针函数的宏,后来可用于WINPROC函数。 为什么ON_COMMAND没有获得WINDOWS句柄...例如,如果程序中有另一个具有相同ID的WINDOW?

第三个也是最后一个,假设我想将一些窗口的线程更改为警报状态。 要做到这一点,我想改变主循环(它继续调用getmessage / dispatchmessage etc ..并插入waitformultibleonject函数。 winmain函数在哪里?当appwizard为我完成所有工作时,我找不到它。

谢谢!

3 个答案:

答案 0 :(得分:2)

在MFC中,消息“冒泡”直到找到处理程序。 IIRC它的观点 - >文件 - >文件模板 - > MainFrame - >应用。这允许处理视图中的视图特定事件,文档中特定于文档的事件等。

通常,全局处理程序最终会出现在大型机类中。但是,您可以使用多个主机窗口 - 即使行为不同 - “MainFrame”和“App类”之间的区别变得很重要。

特定于控件的处理程序确实属于视图类。我只将WM_COMMAND处理程序放入更高级的类中。


对于你的第三个问题:我不会那样做。虽然MFC避免了一些常见的模态循环,但你无法完全避免它们。 OnIdle是实施deferred更新的好地方。


[更新] MFC使用一个全局WNDPROC来处理所有消息。它使用HWND到CWnd映射来定位MFC对象。当WNDPROC看到WM_COMMAND消息时,如果它包含该消息的处理程序,它将首先检查接收器窗口的消息映射。如果没有,它将进行各种检查,例如“这不只是一个CWnd,而是一个CView?”是的 - >获取文档并查看文档消息映射是否具有此特定命令的处理程序。

答案 1 :(得分:0)

打印通常在视图中处理,因为在win32中,您通过将OnPaint事件调用到打印机而不是屏幕来进行打印。此外,对于任何涉及获取鼠标位置的事件,在视图中更容易进行。

您可以轻松地从视图中获取当前的doc文档,但是从视图中获取文档会更加努力。

答案 2 :(得分:0)

MFC框架合理地使用各种消息提供MVC design pattern的基础知识,以提供各部分之间的通信。但是,与任何框架一样,如果您的方法与框架不一致,它提供的结构可以提供许多您不必编写的功能以及相当多的限制和约束。

通常,文档类将处理涉及文档内容更改的消息,视图类将处理涉及文档内容呈现的消息。文档类负责将文档对象的所有数据或内容从文件序列化到文件对象或从文件对象序列化。视图类负责将文档数据视图显示到设备上,例如屏幕上的窗口或打印机。

当文档中的数据发生变化时,可以向文档中注册的所有视图发送消息,通知这些视图数据更改,以便视图可以决定是否对视图进行更改。

框架的第三个主要类,app或应用程序类是文档和视图类的容器和管理器。在app对象中,它是应用程序的入口点(一个也用于MFC DLL以及提供DLL加载和卸载入口点的构造),是主消息泵的钩子。 app类的目的是设置初始环境,然后允许程序员将其特定文档挂钩并将对象查看到app类的MFC框架中。

我的观点是关于对话框处理和帮助处理已放入app类,因为它是放置它的最简单的地方。通常,“关于”是一个对话框,其中包含应用程序的基本描述。 “帮助”和“关于”可能是您想要访问的内容,而无需先启动文档或查看。

这些消息是使用PostMessage()SendMessage()的标准Windows消息,其中包含目标窗口句柄的标准Windows格式,消息标识符以及用于提供其他信息的两个参数。 MFC框架为各种消息标识符提供了许多不同的C预处理器定义。如果您遵循类派生层次结构,您会发现文档类CDocument最终来自CCmdTarget类,就像视图类CViewCView的派生一样,也是。 CCmdTarget反过来来自最基本的MFC类CObject

许多消息映射功能似乎来自CCmdTarget类的功能,它使用接受消息的方法,检查消息标识符是否在CCmdTarget消息列表中特定对象,如果没有将其传递给链中的下一个CCmdTarget对象。因此,MFC框架使用一种Strategy Design Pattern,以便沿着组件链传递消息,直到找到可以处理该消息的对象。

由于MFC框架的时代,相当多的暴露部分使用C预处理器和宏。您可以检查宏以查看它们正在执行的操作以及如何使用Visual Studio IDE实现它们。 MFC框架中作为模板实现的那些部分也可以通过Visual Studio IDE轻松读取。宏和模板都在MFC包含文件中。但是,要读取实际类中的代码,您需要找到MFC源主体的副本。来自Microsoft网站的Using the MFC Source Files提供了一个起点,包括从Visual Studio安装中查找源的位置。

  

Microsoft基础类(MFC)库提供完整的源代码   码。头文件(.h)位于\ atlmfc \ include目录中;   实现文件(.cpp)位于\ atlmfc \ src \ mfc目录中。

我不建议您自行更改。

您的第三个问题是关于线程,您描述的方法在MFC框架中没有意义。使用MFC,您通常会使用AfxBeginThread()AfxBeginThreadEx()函数创建一个线程。有两种线程,一种是用户界面,另一种是没有。多线程应用程序需要修改消息泵是没有意义的。一旦您使用PostThreadMessage()

之类的内容创建了消息,您就会向该线程发送消息

这篇文章Threads with MFC在代码项目中提供了概述和源代码示例。