2009-12-24 54 views
2

有几件事情我不知道的:MFC基本结构问题

当您使用MFC应用程序向导创建一个基本的SDI(姑且称之为TestMfc)你:

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() 

我不明白为w hy MFC是否创建了这种分离? 我看不出为什么应用程序类需要声明处理事件的函数......是不是视图的工作?如果例如几乎没有窗户,它甚至变得更清晰。

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

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

谢谢!

回答

2

在MFC中,消息“冒泡”,直到他们找到一个处理程序IIRC它查看 - >文件 - >文档模板 - >大型机 - >应用这样来处理特定视图视图中的事件,文档中特定于文档的事件等。

通常情况下,全局处理程序会在大型机类中结束。但是,您可以使用多个大型机wi ndows - 即使有不同的行为 - “MainFrame”和“App类”之间的区别变得重要。但是,控件特定的处理程序属于视图类。我只把WM_COMMAND处理程序放到更高级的类中。


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


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

+0

我仍然不明白ONCOMMAND宏如何知道哪些窗口句柄指定处理函数。 我的第三个担心是为了使用APC,我必须插入我的线程以提醒状态以获得那些......所以,除了使用waitformultipleobjects之外,我如何去做这些,这似乎对我来说是正确的 – Idan 2009-12-24 13:50:15

+0

Idan,I已经添加了一些更多的信息的问题。对于另一个问题,最好单独询问。 – peterchen 2009-12-24 20:27:46

0

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

您可以轻松地获得当前的doc格式的看法,但它更多的精力来获取视图形成文档。

0

MFC框架确实提供各种种类的MVC design pattern使用消息的基本知识,以提供各部分之间的通信的一个合理的工作。但是像任何框架,它提供了一种结构,它可以提供大量的功能,你不必写,以及相当多的限制和约束,如果你的做法是不是全等的框架。

一般的文档类将处理涉及对文档的更改内容和视图类将处理涉及文件内容的提示信息的消息。文档类负责将文档对象中的所有数据或内容序列化为文件或从文件中移出文件对象。视图类负责将文档数据的视图显示给屏幕或打印机上的窗口等设备。

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

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

我的意见是关于对话框处理和帮助处理被放到应用程序类中,因为它是最简单的地方。通常情况下,About是一个包含应用程序基本描述的对话框。 “帮助”和“关于”可能是您想要访问的内容,而无需先启动文档或视图。

这些消息是使用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在代码项目中提供了一个概述和源代码示例。