[轉]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);
相關文章
相關標籤/搜索