Windows 应 用 程 序 的 菜 单 可 以 分 成 两 大 类: 程 序 窗口 上 方 菜 单 条 上 的 下 拉 式 菜 单 和 可 以 在 任 意 位 置 显 示 的 弹 出 式 菜 单。 用MFC 建 立 下 拉 菜 单 的 方 法 基 本上 是 相 同 的, 但 建 立 弹 出 式 菜 单 的 方 法 有 很 多。 其中 较 常 用 的 是: 说 明 一 个CMenu 对 象;
用LoadMenu 成 员 函 数 装 入 菜 单 资 源;
用TrackPopupMenu 在 指 定 位 置 显 示 菜 单 并 发 送 所 选 菜 单 项 的ID;
用DestroyMenu 销 毁 菜 单 释 放 资 源。
---- 在 某 些 应 用 程 序 中, 只 有 在 程 序 运 行 时 才 能 根 据情 况 确 定 菜 单 项 的 内 容 和 菜 单 项 的 数 目。 这 样 就 无 法 在 编 程 时 建 立 菜 单 资 源, 也 就 不 能 象 上 面 所 述 的 那样 用LoadMenu 装 入 资 源。 需 要 用 另 一 种 方 法 建 立 菜 单:说 明 一 个CMenu 对 象;
用CreatePopupMenu 建 立 一 个 空 菜 单, 再 用InsertMenu 或AppendMenu加 入 菜 单 项;
用TrackPopupMenu 在 指 定 位 置 显 示 菜 单 并 发 送 所 选 菜 单 项 的ID;
用DestroyMenu 销 毁 菜 单 释 放 资 源。
---- 虽 然 这 种 方 法 可 以 动 态 地 建 立 菜 单, 但 是 能 够 向 动态 菜 单 中 加 入 的 菜 单 项 被 限 制 在 一 个 有 限 的 范 围 内, 并 且 必 须 在 编 程 时 就 确 定 它 们 的ID。 这 是 因 为 按 照MFC 常 规 的菜 单 处 理 机 制, 每 个 菜 单 项 都 要 有 一 个 处 理 函 数, 用MFC 的 消 息 映 射 使 每 个 菜 单ID 对 应 到 相 应 的 处 理 函 数, 从 而 建 立 菜 单 项 与 处 理 函 数 的 对 应 关 系。 用 户 选 中 某 一 菜 单 项, 就 会 触 发 相 应 的 处 理 函 数。 这 样 一 来, 我 们 必 须 在 编程 时 就 知 道 所 有 的 菜 单 项, 它 们 的ID 与 对 应 的 处 理 函 数, 并 用 消 息 映 射 静 态 地 一 一 建 立 对 应 关 系。
---- 在 设 计 程 序 时, 确 实 可 能 出 现 菜 单 项 数 目 无 法 限 制,菜 单ID 事 先 不 能 确 定 的 情 况。 例 如, 一 个 应 用 程 序 有 两 个 文 档 类A 与B, 每 个 文 档 都 可 以 同 时 打 开 任 意 次。 我 们 希望 在 一 个 动 态 菜 单 中, 只 列 出 显 示A 类 文 档 的 窗 口 标 题,另 一 个 动 态 菜 单 中 只 列 出 显 示B 类 文 档 的 窗 口 标 题。 当 选 定 一 个 菜 单 项 时, 对 应 的 文 档 窗 口 显 示 在 最 上 面。 由 于 我 们 不 能 限 制 打 开 的 窗 口 数 目, 也 不 能 预 知 窗 口 标 题, 所 以 就 无 法 确 定 应 该 编 写 多 少 处 理 函 数 以 及 会 有 哪 些 菜 单ID, 当 然 也 就 无 法 用 消 息 映 射 建 立 对 应 关 系。 这 时, 我 们 需 要 一 种 不 使 用 消 息 映 射 的 方 法。 但 是, 不 使 用 消 息 映射 我 们 如 何 知 道 用 户 选 中 了 哪 一 个 菜 单 项 呢 ?
答 案 是CMenu 类 的 成 员 函 数TrackPopupMenu 可 以 告 诉 我 们。
我 们 可 以 从 手 册 或 联 机 帮 助 中 找 到 关 于 该 函 数 的 介 绍:
BOOL TrackPopupMenu(UINT nFlag,int x,int
y,CWnd* pWnd,LPCRECT lpRect=NULL);
---- 参 数nFlag 用 于 指 定 弹 出 式 菜 单 的 位 置 标 志 与 有 效 鼠 标 键。
可 以 取 的 值 为 下 列 的 一 个 或 多 个:
TPM_CENTERALIGN,TPM_LEFTALIGN,TPM_RIGHTALIGN,
TPM_LEFTBUTTON,TPM_RIGHTBUTTON
---- 参 数x,y 为 弹 出 式 菜 单 的 位 置, 参 数pWnd 为 父 窗 口 指 针。
---- 该 函 数 在 指 定 位 置 显 示 一 个 弹 出 式 菜 单, 并 发 送 以 选 中菜 单 项ID 标 识 的 消 息。 执 行 成 功 返 回 非 零 值, 否 则 返 回 零。
---- 这 并 不 是 关 于TrackPopupMenu 的 全 部 信 息。 该 函 数 至 少 有 两个 重 要 特 性 没 有 列 入 文 档, 而 它 们 对 于 解 决 我 们 的 问 题 是至 关 重 要 的。 第 一 个 未 写 入 文 档 的 特 性 是: 该 函 数 的 第 一 个 参 数nFlag 还 可 以 取 另 外 两 个 值:TPM_ NONOTIFY 与TPM_RETURNCMD。
从 它 们 的 名 字 可 以 看 出 来,TPM_ NONOTIFY 的 作 用 是 使TrackPopupMenu 函数 不 发 送 菜 单 消 息 通 知 应 用 程 序。TPM_RETURNCMD 的 作 用 是 使 函 数 将 本 该 发 送 出 去 的 菜 单 消 息 作 为 返 回 值 返 回。 这 时 函 数 的 返回 值 是UINT 类 型 的, 就 是 选 中 的 菜 单ID。 这 就 是 该 函 数 第 二 个未 写 入 文 档 的 特 性
---- 下 面, 我 们 通 过 一 个 例 子 详 细 解 释TrackPopupMenu 的 这 种 用 法。
{
CPoint pt;
GetCursorPos(&pt);
CMenu m_NewMenu;
m_NewMenu.LoadMenu(IDR_MENU_POPUP);//顶级菜单,事先在资源管理器中建好
CMenu* pM = m_NewMenu.GetSubMenu(0);//一级下拉菜单
CMenu *pSubmenu=pM->GetSubMenu(pM->GetMenuItemCount()-1);//二级子菜单
ASSERT(pSubmenu);
UINT nEnable = MF_BYPOSITION|MF_STRING|MF_ENABLED;
for(...){
pSubmenu->InsertMenu(pSubmenu->GetMenuItemCount()-1, nEnable,(UINT_PTR)ID,菜单文字);
}
int SelectID = (HTREEITEM)pM->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL|
TPM_NONOTIFY|TPM_RETURNCMD, pt.x, pt.y, this);
//根据获得的ID作出相应的动作
}