`
isiqi
  • 浏览: 16866252 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

MFC-命令分派

阅读更多

MFC的命令大体上由两类界面元素引发,一种是菜单项,另一种是如按钮,复选框等的通用控件。从消息来看,其实就是处理WM_COMMAND消息。尽管命令消息的进入点仍然是CWnd::OnWndMsg,不过MFC让它走了另一条路,即OnCommand

让命令消息作另外处理是有原因的,比如说菜单命令,往往处理它的并不是FrameWnd,而是ViewDocument或其他的类。所以菜单命令并不是简单的发给拥有菜单的窗口,而是在整个框架绕了一圈。

CWnd::OnCommand调用了OnCmdMsg 这是一个虚函数,不同的类对命令的派发是不一样的,因此各各覆盖OnCmdMsg作具体的处理。

先看看FrameWnd的:

BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,

AFX_CMDHANDLERINFO* pHandlerInfo)

{

// pump through current view FIRST

CView* pView = GetActiveView();

if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE;

// then pump through frame

if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE;

// last but not least, pump through app

CWinApp* pApp = AfxGetApp();

if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

return TRUE;

return FALSE;

}

FrameWnd上的命令大多数是菜单命令,为了让框架中的其他类能够处理菜单命令,它在三个地方调用OnCmdMsg,首先得到处理的是View,其次是FrameWnd自己,最后是WinApp。其实View处理的时候会让Document类处理命令,而Document又会让DocTemplate类处理,如果不中断,整个处理顺序大概是这样的:

CView::OnCmdMsg

CDocument::OnCmdMsg

CDocTemplate::OnCmdMsg

CFrameWnd::OnCmdMsg

pApp->OnCmdMsg

无论上面的类怎么处理,最后的分派都归结到CCmdTarget::OnCmdMsg,这个函数可以简化成这两句代码:

BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,

AFX_CMDHANDLERINFO* pHandlerInfo)

{

if (FindMessageEntry(…))

_AfxDispatchCmdMsg(…)

}

_AfxDispatchCmdMsg真正将消息派发到处理函数去,其做法与CWnd::OnWndMsg是很相似的。

对话框的命令要简单得多,去除其他复杂的因素,甚至可以认为CDialog::OnCmdMsg直接分派消息,也就是只有CDialog的具体子类才能处理它上面的按钮命令。

MFC的命令处理可以应付简单的应用程序,但对于复杂如Office这样的程序,则太过于简陋了。举一个简单的例子,一个对话框有非常多的界面元素,并且这些界面元素要根据数据状态实时更新,利用MFC的命令处理会比较麻烦,因为它没有对话框的实时更新机制。一种理想的方法是这样的,在消息处理Idle的时候,每个界面元素向数据查询状态,这种查询可以认为是非常快速的,根据状态实时更新自己的表现形式,比如EnabledVisible等。这就不仅为命令引入了“执行”的行为,还引入了“更新”的行为。执行和更新是命令机制的基础,看看Office的工具条,如果没有Idle的更新机制,每个按钮的更新可以想象有多么的复杂。

这一点在VCL里面做得比较好,它设计了一套Action的框架,与界面元素最大程度的分离开来,更加集中的处理“执行”和“更新”这种两种行为。每一种界面元素,不管是菜单还是按钮,只要与一个Action挂接,那么它的状态和行为完成由Action来掌管。这样做的好处很多,我列出两个:

1. 多个界面元素可以对应一个Action,这种情况经常出现,比如菜单项与工具栏上的某个按钮,如果它们都挂上同一个Action,则它们的行为和状态都会变得一致。

2. 减少命令与界面的依赖,以后若想换一套新的菜单控件,只要这套控件支持Action机制,则可以在不影响程序行为的情况下轻松更换。

如果是MFC,如何来提供这样的命令机制呢?我想这是考验MFC的可扩展性的时候了。

分享到:
评论

相关推荐

    C++MFC教程

    在MFC中对消息的处理利用了消息映射的方法,该方法的基础是宏定义实现,通过宏定义将消息分派到不同的成员函数进行处理。下面简单讲述一下这种方法的实现方法: 代码如下 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd...

    MFC的程序框架剖析

    这个函数很特殊,它本身是个消息响应函数,当我们点击ID为ID_FILE_NEW的菜单时,会产生一个命令消息,由于命令消息可以被CCmdTarget类及其派生类来捕获,而CWinApp是从CCmdTarget派生出来的,因此可以捕获这个消息。...

    进程管理经典软件MFC

    linux下查看系统进程的命令是ps。 目录 进程的分类1.基本系统进程 2.常见系统进程解释 (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) (23) ...

    2022年自考网络应用程序设计题库答案.docx

    9. SMTP 命令的一般格式是命令关键字 参数 。 10. SMTP 客户问候 SMTP 服务器命令格式是 HELO 发送方的主机名 。 11. 写信字段的格式是 MAIL FROM:发信人电子邮件地址 。 12. 祈求发送邮件内容命令格式:DATA 。 13...

    Win32_API.rar_visual c_win32

    同时,通过WM_CREATE、WM_PAINT、WM_COMMAND等消息响应函数,可以处理窗口创建、重绘、菜单命令等各种事件。 Win32 API的学习需要理解Windows操作系统的基本工作原理,以及C++语言的基础知识。通过深入学习和实践,...

Global site tag (gtag.js) - Google Analytics