MFC 更新命令 UI 机制的端口






4.21/5 (6投票s)
2005年9月14日
2分钟阅读

30515

306
使用事件驱动架构替代 CUpdateUI。
动机
WTL 的 CUpdateUI
违反了 ATL 的策略。BEGIN_MSG_MAP
是一组函数调用,但 WTL 的 BEGIN_UPDATE_UI_MAP
是一组数据。这使得你的程序变得不可控,尤其是在 MDI 应用程序的情况下。参见 WTL 的示例,MDIDocVw。这是不可能理解的。因此,应该替换 CUpdateUI
。
所以,Ketchup.CmdUI 提供了 MFC 更新命令 UI 机制的端口,这是 MFC 仅剩的优点。
要求
- Microsoft Visual C++ .NET 7.1 版
- WTL 版本 7.5
- Boost C++ 库版本 1.33.0 (无需编译)
- Ketchup 消息映射库(获取最新版本)。
快速开始
- 包含头文件
#include "ketchup/cmd_ui.hpp"
- 定义
CmdUI
处理程序void OnUpdateViewStatusBar(ketchup::cmd_ui& ui) { ui.set_check(::IsWindowVisible(m_hWndStatusBar)); }
- 将处理程序添加到消息映射
BEGIN_MSG_MAP(CMDIFrame) // ... KETCHUP_CMD_UI_HANDLER(ID_VIEW_STATUS_BAR, OnUpdateViewStatusBar) END_MSG_MAP()
- 添加 CmdUI 生成器
virtual BOOL OnIdle() { ketchup::update_toolbar_cmd_ui(m_hWnd, m_ToolBar); return FALSE; } BEGIN_MSG_MAP(CMDIFrame) // ... KETCHUP_UPDATE_MENU_CMD_UI() END_MSG_MAP()
Ketchup.CmdUI 是一种事件驱动架构。您可以使用代码而不是数据来确定 UI 的状态。首先,CUpdateUI
与 Win32 不一致。
基本概念
CmdUI
CmdUI
是一个派生自ketchup::cmd_ui
的对象。CmdUI
生成器CmdUI
生成器是生成CmdUI
并将其发送到处理它的窗口的任何东西。- 依赖的
CmdUI
依赖的
CmdUI
是任何没有自己 ID 的CmdUI
。is_dependent
代表依赖关系。
ketchup::cmd_ui
这个类是 MFC 的 CCmdUI 的端口
struct cmd_ui { UINT get_id() const; void set_handled(bool on); bool is_handled() const; virtual void enable(bool on); virtual void set_check(int state); virtual void set_radio(bool on); virtual void set_text(LPCTSTR pszText); virtual void set_default(bool on); virtual bool is_dependent(); };
成员的语义与 CCmdUI 的语义相同,但拒绝使用默认参数。
预定义的 CmdUI 生成器
KETCHUP_UPDATE_MENU_CMD_UI
这是 BEGIN_MSG_MAP
的一个入口,它从菜单项创建 CmdUI
。
ketchup::update_toolbar_cmd_ui
这从工具栏按钮项创建 CmdUI
。
嵌套弹出菜单
从弹出菜单生成的 CmdUI
是依赖 CmdUI
的模型。弹出菜单不能有自己的 ID,因此它依赖于第一个菜单项。参见 MFC 的文档 嵌套弹出菜单。MFC 的语法有些笨拙。ketchup::cmd_ui
提供了一个名为 is_dependent
的成员
void OnUpdatePopupSubmenu(ketchup::cmd_ui& ui) { if (ui.is_dependent()) ui.enable(m_popup_enabled); }
请注意,如果您使用 WTL::CCommandBarCtrl
的 chevron 菜单,所有顶级菜单项(如文件、编辑等)都可以设置为依赖项。
CmdUI 链
提供了 KETCHUP_CHAIN_CLIENT_CMD_UI
和 KETCHUP_CHAIN_MDI_CHILD_CMD_UI
。作用与 WTL 的 CHAIN_CLIENT_COMMANDS
或 CHAIN_MDI_CHILD_COMMANDS
相同。
自动禁用
每个 MDI 子窗口都有不同的命令集。MDI 框架提供动态菜单,但您将如何处理工具栏?如果您想在 MDI 子窗口之间共享菜单,该怎么办?因此,KETCHUP_ENABLE_CMD_UI_IF_HANDLED_BY_MDI_CHILD
会自动链接和禁用 CmdUI
typedef ketchup::idset< ID_BLACK, ID_RED, ID_GREEN, ID_BLUE, ID_WHITE, ID_CUSTOM, ID_SPEED_SLOW, ID_SPEED_FAST > child_cmd_ids; BEGIN_MSG_MAP(CMDIFrame) // ... KETCHUP_ENABLE_CMD_UI_IF_HANDLED_BY_MDI_CHILD(child_cmd_ids) END_MSG_MAP()
MFC 可以根据是否处理 WM_COMMAND
来禁用 CCmdUI,但 WTL 不行。因此,Ketchup.CmdUI 会根据是否处理 CmdUI
来禁用 CmdUI
,也就是说,一个 MDI 子窗口是否有 KETCHUP_CMD_UI_HANDLER
入口。请注意,您应该使用 ketchup::idset
指定目标命令集。