当用户右键单击工具选项板时更改上下文菜单相对简单。派生自。但是,它的方法定义只是返回以避免链接器错误。因此,您必须覆盖接口的两个方法:and。AcadToolImplIAcadToolContextMenuE_NOTIMPLIAcadToolContextMenu::Customize()IAcadToolContextMenu::InvokeMenuCommand()
由于只能在运行时更改上下文菜单,因此必须动态定义菜单命令。当用户右键单击“工具选项板”窗口中的任意选项板时,框架将调用您的实现。它传递菜单句柄、当前调色板的 ID、菜单命令 ID 的上限和下限以及上下文标志。您的实现应执行以下操作:IAcadToolContextMenu::Customize()
- 验证当前工具选项板是否属于您。如果它不是您的,您可能希望通过简单地返回来禁止菜单自定义。E_NOTIMPL
- 如果不想禁止显示更改,请使用菜单句柄添加新命令或删除标准项。
- 确保分配给任何添加项的 ID 在给定范围内。
- 将用于非本地存储的 ID 保存在非本地存储中以供回调引用。
- 当所选工具选项板不属于您时,将缓存的 ID 重新初始化为零。
在每个右键单击事件上,框架都会调用常用工具 COM 对象上的函数。如果应用程序允许用户多次定义常用工具,则可能会无意中重新填充每个定义的上下文菜单。为了防止这种情况,请在创建新实例之前验证常用工具的 GUID 是否不在常用工具目录中。Customize()
如果用户从菜单中选择命令,则会在实现的每个工具对象上调用该方法。调用时,框架会传递所选菜单项的命令 ID、工具选项板 ID 和窗口句柄。如果命令 ID 与您的命令 ID 匹配,并且工具选项板 ID 和窗口控柄可接受,则执行相应的操作。InvokeMenuCommand()IAcadToolContextMenuInvokeMenuCommand()
以下过程使用 MFC 菜单对象将三个菜单项追加到上下文菜单。
设置 IAcadToolContextMenu 实现
- 在simpleTool.h文件中,添加以下预处理器定义:
#define MAX_MENU_ENTRIES 3
- 在simpleTool.cpp文件中,添加以下静态数组来存储您使用的 ID:
static UINT m_nMenuIds[MAX_MENU_ENTRIES] = {0,0,0};
- 在类声明中,声明两个方法的原型:CSimpleToolIAcadToolContextMenu
// IAcadToolContextMenu members
STDMETHOD(Customize)(/* [in] */ int nContextFlag,
/* [in] */ DWORD hMenu,
/* [in] */ UINT idCmdFirst,
/* [in] */ UINT idCmdLast,
/* [in] */ GUID *pPaletteId,
/* [retval][out] */ DWORD *pFlag);
STDMETHOD(InvokeMenuCommand)(/* [in] */ UINT idCmd,
/* [in] */ GUID *pPaletteId,
/* [in] */ DWORD hWnd,
/* [retval][out] */ DWORD *pFlag);
- 在SimpleTool.cpp文件中,为 and 方法添加空白的实现原型。Customize()InvokeMenuCommand()
现在,您已准备好实现上下文菜单功能。
实现 Customize() 方法
- 在实现正文中,检查是否尝试添加的菜单项数超过框架允许的数量:Customize()
int maxMenu = (idCmdLast - idCmdFirst) < MAX_MENU_ENTRIES ? (idCmdLast - idCmdFirst) : MAX_MENU_ENTRIES;
- 使用参数获取当前工具选项板的名称。可以使用对象来检索调色板。以下代码对此进行了演示。pPaletteId*AcTcManager
AcTcPalette* pPalette =
(AcTcPalette*)(AcTcGetManager()->FindItem(*pPaletteId));
ASSERT(pPalette != NULL);
TCHAR pszString[1024]; // arbitrary buffer size; not // limited by the framework
pPalette->GetName(pszString, 1024);
- 将调色板的名称与调色板的名称进行比较。如果发现不匹配,请将菜单 ID 数组条目重新初始化为 0 并返回:
if (_tcscmp(pszString, "SimplePalette")!= 0)
{
for (i=0; i < maxMenu ; i++)
{
m_nMenuIds[i] = 0;
}
return E_NOTIMPL;
}
- 使用步骤 1 中确定的最大菜单项限制保存给定范围内的三个命令 ID:
int i;
for (i=0; i < maxMenu ; i++)
{
m_nMenuIds[i] = idCmdFirst + i;
}
- 创建一个新对象:CMenu
CMenu* menu = new CMenu;
- Attach the object to the context menu, using the parameter and the function:CMenuhMenuCMenu::Attach()
menu->Attach(HMENU(hMenu);
- Add three menu commands, using the selected command IDs:
menu->InsertMenu(-1, MF_BYPOSITION, m_nMenuIds[0], "Menu&1");
menu->InsertMenu(-1, MF_BYPOSITION, m_nMenuIds[1], "Menu&2");
menu->InsertMenu(-1, MF_BYPOSITION, m_nMenuIds[2], "Menu&3");
- Detach the object and delete it:CMenu
menu->Detach();
delete menu;
Here is the finished method override:Customize()
STDMETHODIMP CSimpleTool::Customize(/* [in] */ int nContextFlag,
/* [in] */ DWORD hMenu,
/* [in] */ UINT idCmdFirst,
/* [in] */ UINT idCmdLast,
/* [in] */ GUID *pPaletteId,
/* [retval][out] */ DWORD *pFlag)
{
AcTcPalette* pPalette =
(AcTcPalette*)(AcTcGetManager()->FindItem(*pPaletteId));
ASSERT(pPalette != NULL);
TCHAR pszString[128];
pPalette->GetName(pszString, 128);
int i=0;
int maxMenu = (idCmdLast - idCmdFirst) < MAX_MENU_ENTRIES ?
(idCmdLast - idCmdFirst) : MAX_MENU_ENTRIES;
if (_tcscmp(pszString, "SimplePalette")!= 0)
{
// Zero-out any existing IDs
for (i=0; i < maxMenu ; i++)
{
m_nMenuIds[i] = 0;
}
return E_NOTIMPL;
}
for (i=0; i < maxMenu ; i++)
m_nMenuIds[i] = idCmdFirst + i;
CMenu* menu = new CMenu;
if (menu->Attach(HMENU(hMenu)))
{
menu->InsertMenu(-1, MF_BYPOSITION, m_nMenuIds[0], "Menu&1");
menu->InsertMenu(-1, MF_BYPOSITION, m_nMenuIds[1], "Menu&2");
menu->InsertMenu(-1, MF_BYPOSITION, m_nMenuIds[2], "Menu&3");
menu->Detach();
}
delete menu;
return S_OK;
}
最后一个函数参数 是参数,可用于禁止显示上下文菜单。有关使用此参数的详细信息,请参阅ObjectARX 参考。Customize()pFlag[out,retval]
实现上下文菜单功能的最后一步是重写该方法。对于这个简单的情况,您只需将参数的值与您保存在方法中的菜单 ID 进行比较。如果您找到其中一个 ID,请采取适当的措施。以下代码实现。InvokeMenuCommand()idCmdCustomize()InvokeMenuCommand()
STDMETHODIMP CSimpleTool::InvokeMenuCommand(/* [in] */ UINT idCmd,
/* [in] */ GUID *pPaletteId,
/* [in] */ DWORD hWnd,
/* [retval][out] */ DWORD *pFlag)
{
if (idCmd == m_nMenuIds[0])
::AfxMessageBox("Menu1 chosen");
else if (idCmd == m_nMenuIds[1])
::AfxMessageBox("Menu2 chosen");
else if (idCmd == m_nMenuIds[2])
::AfxMessageBox("Menu3 chosen");
return S_OK;
}
|