[转]objectarx 加载菜单-ObjectARX中右键(快捷)菜单的实现方法

批注:
由网文整理而成,原文地址 http://blog.csdn.net/kyfvc/article/details/9121737
其中一些API已经有更方便的替代品了,好比push/popResource 已经有了 CAcModuleResourceOverride
另外 有些地方的push/pop资源是否须要也待商榷。
具体区别能够对照ObjectARX 2012 Sample中 ArxDbg编程

  右键菜单,也叫快捷菜单,在Windows编程中叫上下文(context)菜单。
  
  ObjectARX自己提供了一套处理上下文菜单的机制。在ObjectARX类库中有一个名为AcEdUIContext的类,此类负责在ObjectARX应用中的上下文菜单中添加本身的菜单项,而原菜单项不会被破坏,这也是此种方法的优势之一。用AcEdUIContext类添加菜单时,菜单项的数目没有限制,但必须是文本菜单。菜单能够层叠,但不容许使用键盘加速键,不可以在状态行显示快捷菜单命令状态提示。数组

此类能够处理三种状况下的上下文菜单:编辑器

  • 一个默认上下文菜单,
  • 二是实体对象上下文菜单,
  • 三是命令执行时上下文菜单。

虽然菜单出现的时机不一样,但方法基本相同,它们之间主要的不一样是所用的加载和卸载函数不一样。下面加以详细介绍。ide

  在AcEdUIContext为中包含了三个重要的成员函数,他们分别是:函数

  • (1) AutoCAD系统获取快捷菜单句柄函数
virtual void * getMenuContext(const AcRxClass * unnamed,const AcDbObjectIdArray& unnamed) = 0;

其中,第一个参数unnamed 是当前所选择的实体的对象句柄,第二个参数unnamed是所选实体的实体ID数组。这两个参数只有在实体对象上下文菜单中有效。.net

  • (2) 菜单项命令事件响应函数
virtual void onCommand(Adesk::UInt32 unnamed) = 0;

其中,unnamed是相应菜单项的菜单ID。此函数在用户选择执行快捷菜单中的某个菜单项时被调用。指针

  • (3) 菜单更新函数
virtual void OnUpdateMenu();

AutoCAD在快捷菜单弹出以前调用此函数。至关于MFC中的菜单更新事件,咱们能够在这个函数中改变菜单项的检查状态或使能菜单项等。code

其实,咱们利用ObjectARX实现上下文菜单要作的工做主要是重载并填写这几个AcEdUIContext成员函数,其操做方法以下:orm

  • 首先,咱们从AcEdUIContext类派生一个本身的类,名字就叫CDefaultContextMenu吧,固然,你能够按本身的喜爱起名字了:-)。而后,在派生的类中重载以上三个函数。
class CDefaultContextMenu: public AcEdUIContext
{
public:
CDefaultContextMenu();
~CDefaultContextMenu();

// 以下重载如下三个函数
virtual void* getMenuContext(const AcRxClass *pClass, const AcDbObjectIdArray& ids) ;
virtual void onCommand(Adesk::UInt32 cmdIndex);
virtual void OnUpdateMenu();

private:
CMenu *m_pDemoMenu; // 用来增长菜单项的MFC菜单对象,使用它是为了加载咱们在VC中增长的菜单资源。
HMENU m_hDemoMenu; // 菜单项所对应的句柄,这才是咱们真正要加载的的菜单项,它是m_pDemoMenu中的一项。
};

  接下来咱们须要作的是:对象

  • (1)在构造函数中加载菜单资源;
acDocManager->pushResourceHandle(_hdllInstance); // 切换当前使用的资源,千万不要忘记加上吆!_hdllInstance是模块
//实例指针,经过extern引用到使用的位置就能够了。
m_pDemoMenu= new CMenu; // 建立一个菜单对象
m_pDemoMenu->LoadMenu(IDR_DEMO_DEFAULT_MENU); // 使用建立的菜单对象加载在资源编辑器中编辑好的资源
acDocManager->popResourceHandle(); // 再把资源切换回来吧!
  • (2)在getMenuContext函数中添加显示咱们本身菜单项的代码;
m_hDemoMenu= m_pDemoMenu->GetSubMenu(0)->GetSafeHmenu(); //这里咱们就显示已经加载的菜单(m_pDemoMenu)中的第一个子菜单吧!
return &m_hDemoMenu; // 返回子菜单对象的句柄
  • (3)在onCommand函数中处理命令执行代码;
acDocManager->pushResourceHandle(_hdllInstance); // 切换当前使用的资源

CString strMenuTitle, strPrompt;
m_pMenu->GetMenuString(cmdIndex,strMenuTitle,MF_BYCOMMAND); // 获取一所选菜单项的文本标题
strPrompt.Format("\n您已经选取了菜单:%s\n",strMenuTitle);
acutPrintf(strPrompt); // 咱们的例子显示哪个菜单项被选择
acedPostCommandPrompt(); // 显示命令提示

acDocManager->popResourceHandle(); // 将资源切换回来
  • (4)在OnUpdateMenu中修改菜单项的显示状态(此步可选可不选);
m_pDemoMenu->EnableMenuItem(IDR_DEMO_DEFAULT_MENU_ITEM1,MF_GRAYED); // 使菜单变灰
m_pDemoMenu->EnableMenuItem(IDR_DEMO_DEFAULT_MENU_ITEM2,MF_ENABLED); // 使能菜单项
m_pDemoMenu->CheckMenuItem(IDR_DEMO_DEFAULT_MENU_ITEM3, MF_BYCOMMAND|MF_CHECKED); // 复选菜单项
  • (5)在析构函数中卸载资源。
if (m_pMenu) delete m_pMenu; // 不释放的话麻烦可大呀!!!

  以上用默认上下文菜单为例对AcEdUIContext类的使用方法做了阐述,至于其余两种基本是与默认上下文菜单相同。只不过在实体对象上下文菜单中的getMenuContext函数中能够对所选的实体进行响应,由于咱们能够经过getMenuContext函数的参数获取实体对象。

  有了以上的准备工做,咱们就能够按照菜单显示时机加载不一样种类的菜单了。

  • 首先,要行声明一个全局的上下文菜单对象,以下:
CDefaultContextMenu *gpDefDemoCM; // 默认上下文菜单
CEntityContextMenu *gpEntDemoCM; // 实体对象上下文菜单
CCmdContextMenu *gpCmdDemoCM; // 命令时上下文菜单
  • 而后,在初始化ARX应用时建立并加载上下文菜单对象。
gpDefDemoCM = new CDefaultContextMenu; // 建立默认上下文菜单
gpEntDemoCM = new CEntityContextMenu; // 建立实体对象上下文菜单
gpCmdDemoCM = new CCmdContextMenu; // 建立命令时上下文菜单

acDocManager->pushResourceHandle(_hdllInstance); // 切换当前使用的资源

acedAddDefaultContextMenu(gpDefDemoCM, pAppID); // 向AutoCAD应用中添加默认上下文菜单

acedAddObjectContextMenu(AcDbEntity::desc(), gpEntDemoCM , pAppID); // 向AutoCAD应用中添加实体对象上下文菜单

// 向AutoCAD应用中添加命令时上下文菜单
// myCmd是一个命令函数。第一个参数是命令组名,第二个参数是全局命令名,
// 第三个参数是本地命令名,第四个参数是命令模式,第5和6个参数就不用说了,你们应该明白了。:-0
acedRegCmds->addCommand("MyGrp", "MyDemo", "MyDemo", ACRX_CMD_MODAL, &myCmd, gpCmdDemoCM );

acDocManager->popResourceHandle(); // 切换回资源

说明:pAppID是acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)中是第二个参数。acedAddObjectContextMenu中的第一个参数根据实体的不一样而不一样,如对于线实体则为AcDbLine::desc()等。

  • 最后,在卸载ARX应用时,将加载的上下文菜单对象移除,并释放内存空间。
HINSTANCE hInst = AfxGetResourceHandle(); // 保证资源正确
AfxSetResourceHandle(_hdllInstance);

acedRemoveDefaultContextMenu(gpDefDemoCM ); // 移除默认上下文菜单
acedRemoveObjectContextMenu(AcDbEntity::desc(), gpEntDemoCM ); // 移除实体对象上下文菜单
acedRegCmds->removeGroup("MyGrp"); // 移除命令组"MyGrp"

delete gpDefDemoCM;
delete gpEntDemoCM;
delete gpCmdDemoCM;

AfxSetResourceHandle(hInst);
相关文章
相关标签/搜索