TN021:命令和消息路由

备注

以下技术声明,则它在联机文档,首先包括了不更新。因此,某些过程和主题可能已过时或不正确。有关最新信息,建议您搜索议题在联机文档的索引。

此说明在常规窗口消息路由描述命令传送和计划体系结构以及高级主题。

请参见 Visual C++ 有关在此处,特别是中描述的体系结构的泛型详细信息 " 窗口消息之间的区别,控件通知和命令。 此说明假定您熟悉非常问题描述在打印的文档和仅解决非常高级主题。

命令传送和计划 MFC 1.0 功能发展到 MFC 2.0 体系结构

窗口有重载提供菜单命令、快捷键和对话框控件通知的通知 WM_COMMAND 消息。

每次 1.0 生成的 MFC 一点通过允许命令处理程序 (例如, “OnFileNew”) 在 CWnd 派生类会调用以响应特定 WM_COMMAND。 这与在一个非常空间利用率的命令结构的数据结构调用消息映射中的和结果一起胶合。

分隔的控件通知 MFC 1.0 还提供了附加功能从命令消息。 命令以 16 位 ID 表示,有时称为命令 ID. 命令从 CFrameWnd (即选择的菜单或转换的快捷键) 通常启动并将其路由到各种其他窗口。

MFC 1.0 在受限必要使用了命令传送为多个文档的实现接口 (MDI)。 (MDI 框架窗口中键入命令到其活动的 MDI 子窗口。)

此函数在 MFC 2.0 泛化和扩展允许命令由各种各样的对象 (不仅仅是 windows 对象) 处理。 它用于将消息传送提供更为正式和更可扩展的结构并重新使用命令目标路由不处理指令,,而且更新的 UI 对象 (如菜单项和工具栏按钮) 以反映当前命令的可用性。

命令 ID

为命令传送的声明参见 Visual C++ 和绑定过程。 技术说明 20 包含有关 ID 命名的信息。

我们为命令 ID 使用泛型标题 “ID_”。 命令 ID 是 >= 0x8000。 ,如果有 ID 的一种 STRINGTABLE 资源和命令 ID. 相同,消息行或状态栏将显示命令描述字符串

在应用程序资源,命令 ID 可以访问于多个位置出现:

  • 在具有 ID 和消息行提示相同的一种 STRINGTABLE 资源。

  • 在可以附加到菜单项调用相同的命令的多个菜单资源。

  • (高级) 在 GOSUB 命令的一个对话框按钮。

在应用程序的源代码,命令 ID 可以访问于多个位置出现:

  • 在您的) 定义特定的命令 ID 的 RESOURCE.H (或其他主符号头文件。

  • 可能在所使用的 ID 数组创建工具栏。

  • ON_COMMAND 宏。

  • 可能位于 ON_UPDATE_COMMAND_UI 宏。

目前,在需要命令 ID 的 MFC 的唯一实现是 >= 0x8000 是 GOSUB 对话框/命令的实现。

GOSUB 命令,使用在对话框的命令体系结构

路由和启用指令体系结构适用于框架窗口,菜单项,工具栏使用按,对话栏按钮,旨在的其他控件条和其他用户界面元素更新按需和路由命令或控件 ID 到主命令目标 (通常是主框架窗口)。 主命令目标上路由命令或控件通知给其他命令将面向对象根据需要。

对话框 (模式或无模式) 受益某些命令体系结构的功能,如果将对话框控件的控件 ID 到相应的命令 ID. 对于对话框支持不是自动的,因此,您可能必须编写一些附加代码。

注意对于所有这些功能正常工作,您的命令 ID 应为 >= 0x8000。 由于许多对话框会路由到同一帧,共享命令应是 >= 0x8000,,而特定对话框的共享 IDCs 应为 <= 0x7FFF。

您使用按钮的 IDC 的普通模式对话框可以将矩形按钮设置为适当的命令 ID. 当用户选择该按钮时,对话框 (通常是主框架窗口) 的所有者获取命令与任何其他命令。 这称为 GOSUB 命令,因为它通常用于引发另一个对话框 (第一个对话框的 GOSUB)。

还可以调用您的对话框的函数 CWnd::UpdateDialogControls 并将其自己的主框架窗口地址。 此函数将启用或禁用应用程序基于的对话框控件它们是否具有命令处理程序在框架。 此功能为您自动调用在应用程序中空闲循环的控件条,但是,您必须调用它直接规则对话框的想要获取此功能。

当 ON_UPDATE_COMMAND_UI 调用

启用所需要的维护/签出状态过程的所有菜单项可始终是一个消耗的计算问题。 ,只有当用户选择弹出时,一种常用方法是启用/检查菜单项。 CFrameWnd 处理的 MFC 2.0 实现 WM_INITMENUPOPUP 消息和使用命令传送体系结构放置 menu 状态。 ON_UPDATE_COMMAND_UI 处理程序。

CFrameWnd 处理描述当前菜单项的 WM_ENTERIDLE 选择消息在状态栏 (也称为消息行)。

应用程序菜单结构,编辑由 Visual C++,用于表示潜在的中的可用命令 WM_INITMENUPOPUP 时间。 ON_UPDATE_COMMAND_UI 处理程序可以修改菜单状态或文本,或者为高级使用 (如文件 MRU 列表或 OLE 谓词弹出菜单),实际修改菜单结构,在绘制前菜单。

同一排序 ON_UPDATE_COMMAND_UI 处理为工具栏 (和其他控件条) 时,将执行应用程序输入其空闲循环时。 请参见 类库参考技术说明 31 有关控件条的更多信息。

嵌套的弹出菜单

如果使用嵌套的菜单结构,您将注意到第一个菜单项的 ON_UPDATE_COMMAND_UI 处理程序在弹出菜单在两个不同大小写的调用。

首先,它为弹出菜单调用。 这是必需的,因为弹出菜单没有 ID,我们使用弹出菜单的第一个菜单项的 ID 引用整个弹出菜单。 在这种情况下, CCmdUI 对象的 m_pSubMenu 成员变量非 null,并指向弹出菜单。

接下来,在中,将绘制前,它调用在弹出菜单的菜单项。 在这种情况下, ID 引用第一个菜单项,并 CCmdUI 对象的 m_pSubMenu 成员变量将为空。

这使您得以将弹出菜单清单从其菜单项,但是,要求您编写菜单识别代码。 例如,在包含以下结构的嵌套菜单:

File>
    New>
        Sheet (ID_NEW_SHEET)
        Chart (ID_NEW_CHART)

ID_NEW_SHEET 和 ID_NEW_CHART 命令可以独立地启用或禁用。 新建 弹出菜单,如果之一个已启用,应启用。

ID_NEW_SHEET (在弹出的第一个命令的命令处理程序) 会类似于:

void CMyApp::OnUpdateNewSheet(CCmdUI* pCmdUI)
{
    if (pCmdUI->m_pSubMenu != NULL)
    {
        // enable entire pop-up for "New" sheet and chart
        BOOL bEnable = m_bCanCreateSheet || m_bCanCreateChart;

        // CCmdUI::Enable is a no-op for this case, so we
        //   must do what it would have done.
        pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex,
            MF_BYPOSITION | 
                (bEnable ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
        return;
    }
    // otherwise just the New Sheet command
    pCmdUI->Enable(m_bCanCreateSheet);
}

ID_NEW_CHART 的命令处理程序会定期更新命令处理程序和类似于:

void CMyApp::OnUpdateNewChart(CCmdUI* pCmdUI)
{
    pCmdUI->Enable(m_bCanCreateChart);
}

ON_COMMAND 和 ON_BN_CLICKED

ON_COMMANDON_BN_CLICKED 的消息映射宏相同。 MFC 命令和控件通知路由结构在何处只使用命令 ID 决定路由。 控件与控件通知代码的通知零 (0)BN_CLICKED) 被解释为命令。

备注

实际上,所有控件通知消息的命令处理程序链。例如,对于您在技术上可以为 EN_CHANGE 的控件通知处理程序在文档类中编写。这不是通常建议的,因为此功能的实际应用是少,函数不是由类向导支持,因此,函数的使用会导致脆弱的代码。

禁用自动禁用按钮控件

如果将一个按钮控件在对话栏,或在单独调用 CWnd::UpdateDialogControls 的对话框使用,您将注意到没有 ON_COMMANDON_UPDATE_COMMAND_UI 处理程序的按钮以将自动禁用由框架。 有时,不需要有一个处理程序,但是,您将需要该按钮将启用。 最简单的方法要么实现这不会添加一条假的命令处理程序 (轻松执行与类向导) 和执行用它。

windows 消息路由

下面描述在 MFC 类的某些高级主题,并且 windows 消息路由和其他主题介绍如何影响它们。 此处的信息只简要介绍。 请参见有关公共 API 的详细信息, 类库引用 " 中 的。 请参见 MFC 库源代码有关实现详细信息的更多信息。

请参见 技术说明 17 有关 windows 清理的详细信息,所有 CWnd的非常重要的主题派生类。

CWnd 问题

实现成员函数 CWnd::OnChildNotify 为子窗口 (也称为控件) 提供了功能强大、可扩展结构允许挂钩或通告的消息、命令和转到其父控件的通知 (或 “所有者”)。 如果子窗口 (/control) 是 c. C++ CWnd 对象,虚函数 OnChildNotify 首先调用与原始消息 (即 MSG 结构) 的参数。 子窗口可能不理会消息,就餐它或修改父的消息 (极少见)。

默认 CWnd 实现处理 OnChildNotify 挂钩允许子窗口的信息和使用 (控件) 添加到第一访问消息:

  • WM_MEASUREITEMWM_DRAWITEM (对于自绘制)

  • WM_COMPAREITEMWM_DELETEITEM (对于自绘制)

  • WM_HSCROLLWM_VSCROLL

  • WM_CTLCOLOR

  • WM_PARENTNOTIFY

您将 OnChildNotify 挂钩用于更改所有者描述消息用来自绘制消息的通知。

除了 OnChildNotify 挂钩外,滚动消息有进一步的路由行为。 有关更多详细信息下面请参见 " WM_HSCROLLWM_VSCROLL 消息的滚动条和源。

CFrameWnd 问题

CFrameWnd 类提供更新实现的大部分命令传送和用户界面。 对于应用程序主要用途 (CWinApp::m_pMainWnd) 的主框架窗口,但适用于所有框架窗口。

主框架窗口是具有菜单栏的窗口并为状态栏或消息行的父级。 请参见有关路由和 **WM_INITMENUPOPUP.**的上面讨论

CFrameWnd 类提供事件视图的管理。 以下信息通过活动视图路由:

  • 所有命令消息 (活动视图获取对它们的第一个访问)。

  • 来自同级滚动条 (下文) 的WM_HSCROLLWM_VSCROLL 消息。

  • MDI 的WM_ACTIVATE (和 WM_MDIACTIVATE ) 获取启用到调用虚函数 CView::OnActivateView

CMDIFrameWnd/CMDIChildWnd 问题

两个 MDI 框架窗口类从 CFrameWnd 派生并为相同启用对 CFrameWnd和用户界面更新提供的命令传送。 在典型的 MDI 应用程序,只有主框架窗口 (即 CMDIFrameWnd 对象) 保存菜单栏和状态栏和是命令传送实现的主要源。

泛型路由模式是活动的 MDI 子窗口获取对命令之一访问。 MDI 子窗口的默认 PreTranslateMessage 函数处理快捷键对应表 (第) 和 MDI 框架 (接下来) 和 TranslateMDISysAccel 通常处理标准 (fips) MDI 系统命令快捷键 (前)。

滚动条问题

在处理滚动消息 (WM_HSCROLL/OnHScrollWM_VSCROLL/OnVScroll) 时,应尝试编写处理程序代码,因此它不依赖于滚动条消息来自何处。 这是常规窗口不仅问题,,因为滚动消息可以来自 true 滚动条控件或 WS_HSCROLL/WS_VSCROLL 不是滚动条控件的滚动条。

MFC 扩展这允许滚动条控件是移动的窗口的子级或同级 (实际上,移动的父/子关系滚动条和之间窗口可以是任何)。 这对于使用拆分窗口的共享滚动条特别重要。 请参见 技术说明 29 有关 CSplitterWnd 实现的详细信息包括有关共享滚动条问题的更多信息。

在旁注,有两 CWnd 派生类滚动条样式指定在创建时捕获和未传递到窗口中的位置。 当传递给创建实例, WS_HSCROLLWS_VSCROLL 可以独立地设置,但是,中,不能更改之后创建。 当然,您不应直接测试或设置 WS_? 将它们创建窗口的样式位。

CMDIFrameWnd 滚动条样式传递给 创建LoadFrame 用于创建 MDICLIENT。 如果想要获取可滚动 MDICLIENT 区域 (如窗口管理器) 请确保将两个滚动条样式 (WS_HSCROLL |WS_VSCROLL中使用的样式创建 CMDIFrameWnd

CSplitterWnd 滚动条样式应用于拆分区域的特定共享滚动条。 对于静态拆分窗口,通常不设置任何一个滚动条样式。 对于动态拆分窗口,通常将滚动条样式设置为您要拆分的方向,也就是说, WS_HSCROLL ,则可以拆分行, WS_VSCROLL ,则可以拆分列。

请参见

其他资源

由Number "技术说明

技术说明按类别