![]() |
【转帖】[原创]objectarx中右键(快捷)菜单的实现方法
[原创]objectarx中右键(快捷)菜单的实现方法
[原创]objectarx中右键(快捷)菜单的实现方法 [原创]objectarx中右键(快捷)菜单的实现方法 作者:3stech 网上看到好像网友问到在autocad窗口中实现右键菜单的方法,觉得这种技术很实用,在许多开发应用中都能用得到,所以就写了这篇文章,以供大家参考。由于本人水平有限,不对之处敬请原谅。 据本人理解,右键菜单,也叫快捷菜单,在windows编程中叫上下文(context)菜单。objectarx本身提供了一套处理上下文菜单的机制。在objectarx类库中有一个名为aceduicontext的类,此类负责在objectarx应用中的上下文菜单中添加自己的菜单项,而原菜单项不会被破坏,这也是此种方法的优点之一。用aceduicontext类添加菜单时,菜单项的数目没有限制,但必须是文本菜单。菜单可以层迭,但不允许使用键盘加速键,不能够在状态行显示快捷菜单命令状态提示。此类可以处理三种情况下的上下文菜单:一个默认上下文菜单,二是实体对象上下文菜单,三是命令执行时上下文菜单。虽然菜单出现的时机不同,但方法基本相同,它们之间主要的不同是所用的加载和卸载函数不同。下面加以详细介绍。 在aceduicontext为中包含了三个重要的成员函数,他们分别是: (1) autocad系统获取快捷菜单句柄函数 virtual void * getmenucontext(const acrxclass * unnamed,const acdbobjectidarray& unnamed) = 0; 其中,第一个参数unnamed 是当前所选择的实体的对象句柄,第二个参数unnamed是所选实体的实体id数组。这两个参数只有在实体对象上下文菜单中有效。 (2) 菜单项命令事件响应函数 virtual void oncommand(adesk::uint32 unnamed) = 0; 其中,unnamed是相应菜单项的菜单id。此函数在用户选择执行快捷菜单中的某个菜单项时被调用。 (3) 菜单更新函数 virtual void onupdatemenu(); autocad在快捷菜单弹出之前调用此函数。相当于mfc中的菜单更新事件,我们可以在这个函数中改变菜单项的检查状态或使能菜单项等。 其实,我们利用objectarx实现上下文菜单要做的工作主要是重载并填写这几个aceduicontext成员函数,其操作方法如下: 首先,我们从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)在构造函数中加载菜单资源;(2)在getmenucontext函数中添加显示我们自己菜单项的代码;(3)在oncommand函数中处理命令执行代码;(4)在onupdatemenu中修改菜单项的显示状态(此步可选可不选);(5)在析构函数中卸载资源。 --在构造函数中加载菜单资源 acdocmanager->pushresourcehandle(_hdllinstance); // 切换当前使用的资源,千万不要忘记加上吆!_hdllinstance是模块 //实例指针,通过extern引用到使用的位置就可以了。 m_pdemomenu= new cmenu; // 创建一个菜单对象 m_pdemomenu->loadmenu(idr_demo_default_menu); // 使用创建的菜单对象加载在资源编辑器中编辑好的资源 acdocmanager->popresourcehandle(); // 再把资源切换回来吧! --在getmenucontext函数中添加显示我们自己菜单项的代码 m_hdemomenu= m_pdemomenu->getsubmenu(0)->getsafehmenu(); // 这里我们就显示已经加载的菜单(m_pdemomenu)中的第一个子菜单吧! return &m_hdemomenu; // 返回子菜单对象的句柄 --在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(); // 将资源切换回来 --在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); // 复选菜单项 --在析构函数中卸载资源 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); 到此为止,我们的所有代码都已经编写完毕了,不过你别忘记了创建菜单资源吆!不知道你是否已经掌握了呢?如有问题的话欢迎在本站()发帖询问。如果有什么意见或建议呢,也希望您给予批评指正。 请问,有人依照本例实现功能?我在右键时只多出一条分割线,不知道问题出在那儿? 恳请大家指点 qq:19154480 msn:freejustinji@hotmail.com e-mail:justin3@citiz.net 试试看! 太晚了,天亮再试 |
| 所有的时间均为北京时间。 现在的时间是 03:11 AM. |