objectarx arxdbg into

01、acedAddDefaultContextMenu 添加右键菜单项

Adesk::Boolean acedAddDefaultContextMenu(
    AcEdUIContext * pContext, 
    const void * appId, 
    const ACHAR* appName = NULL
);

aced.h

Parameters
Description
AcEdUIContext * pContext
Pointer to AcEdUIContext callback class
const void * appId
Pointer passed in by AutoCAD in acrxEntryPoint when application receives kInitAppMsg
const ACHAR* appName = NULL
Optional name that will become submenu item in the default mode shortcut menu

This function adds a default mode shortcut menu (AcEdUIContext instance).

The appName should be based on the name of the ObjectARX application. If an appName is not given, the filename of the application will be used.

Returns Adesk::kTrue if successful; otherwise, returns Adesk::kFalse.

sample http://www.cnblogs.com/kevinzhwl/p/3894781.html#undefined

[转]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类添加菜单时,菜单项的数目没有限制,但必须是文本菜单。菜单可以层叠,但不允许使用键盘加速键,不能够在状态行显示快捷菜单命令状态提示。

此类可以处理三种情况下的上下文菜单:

一个默认上下文菜单,
二是实体对象上下文菜单,
三是命令执行时上下文菜单。
虽然菜单出现的时机不同,但方法基本相同,它们之间主要的不同是所用的加载和卸载函数不同。下面加以详细介绍。

  在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)在构造函数中加载菜单资源;
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);
//对应的取消注册菜单

acedRemoveDefaultContextMenu 

02、AcEdUIContext 

AcRxObject

AcEdUIContext

C++
class AcEdUIContext : public AcRxObject;

aced.h

This class is used by ObjectARX applications to add items to AutoCAD shortcut (context) menus.

Default Mode

When no command is running, there is no pick first selection set, and the user right-clicks for a shortcut menu, the menu will contain some standard items read from the CMDEFAULT POP menu in the CUI file. If there are loaded ObjectARX applications that wish to append items to this shortcut menu, they can do so. Any number of loaded ObjectARX applications can supply HMENUs and callback functions for items that will appear in the shortcut menu as a submenu. The top-level item (submenu name) will be the name of the ObjectARX application if no submenu name is provided. The ObjectARX application must return an HMENU* when AutoCAD calls the getMenuContext() member function of the AcEdUIContext object that the application has added. If the user picks one of these appended items, AutoCAD calls the onCommand() member function of the AcEdUIContext object with the ID associated with that item that was in the HMENU provided as the argument.

Use acedAddDefaultContextMenu() to add an AcEdUIContext instance to the default mode shortcut menu, and acedRemoveDefaultContextMenu() to remove one.

Edit Mode

When a pick first selection set exists and the user right clicks for a shortcut menu, the menu will contain some standard items read from the CMEDIT POP menu in the CUI file. In addition, the selected object(s) can append items to the menu. Each AcRxClass in the hierarchy of an object can contain an AcEdUIContext object. The shortcut menu code determines a common parent for all objects in the selection set. Starting with that class and going up the class hierarchy, it queries each class for an AcEdUIContext object and then appends items to the shortcut menu from the supplied HMENU. In this way, each class in an object's class hierarchy can contribute items to a shortcut menu. The ObjectARX application must return an HMENU* when AutoCAD calls the getMenuContext() member function of the AcEdUIContext object it retrieves from the class hierarchy. If the user picks one of these appended items, AutoCAD calls the onCommand() member function of the AcEdUIContext object for the object that provided the menu item, using the ID associated with that item in the HMENU as the argument.

Use acedAddObjectContextMenu() to add an AcEdUIContext instance to an object, and acedRemoveObjectContextMenu() to remove one.

Command Mode

When an ObjectARX command is running and the user right clicks for a shortcut menu, the menu will contain some standard items read from the CMCOMMAND POP menu in the CUI file. In addition, if the command prompt issued by the ObjectARX application has command options in it and the command prompt uses the standard syntax, these options will appear as individual items in the shortcut menu. When the user picks a command option from the shortcut menu, the option keyword will be sent to the current command throat. These command options are always added to the shortcut menu and the ObjectARX developer need only provide a command prompt in standard form to get this functionality.

If the ObjectARX application wishes to append additional items to the shortcut menu for a particular command, it must supply an HMENU* and a callback function to AutoCAD. An AcEdUIContext object for an ObjectARX command object is specified using the UIContext argument of AcEdCommandStack::addCommand. The ObjectARX application must return an HMENU* when AutoCAD calls the getMenuContext() member function of the AcEdUIContext object it retrieves from the ObjectARX command object. The menu items in the HMENU provided are appended to the shortcut menu for that command. If the user picks one of these appended items, AutoCAD calls the onCommand() member function of the AcEdUIContext object for that command with the ID associated with that item that was in the HMENU provided as the argument.

There is no limit on the number of menu items, but items should contain only text. Cascading menus are allowed. Shortcut menu items provided by ObjectARX applications should contain no keyboard accelerators. No status line menu item help is displayed for these added items.

acedAddDefaultContextMenu(), acedRemoveDefaultContextMenu(), acedAddObjectContextMenu(), acedRemoveObjectContextMenu(), AcEdCommandStack::addCommand

  Comments?

Copyright ©2013 Autodesk, Inc. Generated on: January 24, 2013


AcRxObject

03 AcRxClass

AcRxValueType
C++
class AcRxClass : public AcRxObject;

rxclass.h

AcRxClass objects (actually objects of an internal class derived from AcRxClass, since AcRxClass is an abstract base class) are used as the nodes in the ObjectARX runtime class hierarchical tree. Each instance of an AcRxClass represents a C++ class derived from AcRxObject (or AcRxObject itself). The run-time information about such C++ classes and their hierarchical relationships is available through the AcRxClass objects that make up the runtime tree.

For each class, AcRxClass maintains the following information about the C++ class it represents:

  • Set of immediately derived classes
  • Parent class
  • Class ASCII name
  • Class DXF name, if it is derived from AcDbObject
  • Class 'application' name, in case other applications need to prompt for loading of an application
  • Set of 'protocol extension' objects attached.









Menu 重设置 popup true 则可以保护子菜单项目

设置各个菜单项目的Id 在Oncommand里面来处理

监听到发送了哪个Id对应执行对应的命令。。。

【AcEdUIContext的三个命令的使用】

getMenuContext:获取菜单的hwnd

oncommand :命令触发的操作 发送命令给cad执行

isValid :命令是否可用

  

void  
ArxDbgEdUiContextApp::onCommand(Adesk::UInt32 cmdId)
{
	LPCTSTR cmdStr = NULL;
	CString str;

	if (cmdId == ARXDBG_APPCMD_EDITOR_INFO)
		cmdStr = _T("ArxDbgSnoopEd");
        else if (cmdId == ARXDBG_APPCMD_ABOUT)
		cmdStr = _T("ArxDbgAbout");

	if (cmdStr != NULL) {
		str.Format(_T("%s\n"), cmdStr);
	    acDocManager->sendStringToExecute(acDocManager->curDocument(), str, false, false);
	}
}


 ArxDbgApp::registerClasses:


ArxDbgApp::registerClasses:
 call rxInit on all classes we have defined that are derived
 from AcRxObject or any of its descendants

   This function is used to rebuild the ObjectARX runtime class tree when new classes need to be added. It can be safely called at any time, but is necessary only after the rxInit() functions have been called for any classes to be added to the runtime tree. This is usually done inside the AcRx::kInitAppMsg case of the acrxEntryPoint() switch statement (or a function called from there). This function needs to be called only once after all the rxInit() calls have been made.


Objectarx流程

开始

AcRx::AppRetCode
ArxDbgApp::initApp()
{
    acrxUnlockApplication(m_acadAppPtr);
    acrxDynamicLinker->registerAppMDIAware(m_acadAppPtr);


        // get the name of this app so we can find where other
        // things are located.
    CString appFileName = acedGetAppName();


    TCHAR dir[_MAX_DIR], drive[_MAX_DRIVE], path[_MAX_PATH];
    _tsplitpath_s(appFileName, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0);
    _tmakepath(path, drive, dir, NULL, NULL);
    m_appPath = path;


CWnd* splashScreen = startSplashScreen();


    registerClasses();//注册继承自objectarx的类
    registerCommands();//注册项目里面的命令
    acrxBuildClassHierarchy();//新的类注册完成之后调用

This function is used to rebuild the ObjectARX runtime class tree when new classes need to be added. It can be safely called at any time, but is necessary only after the rxInit() functions have been called for any classes to be added to the runtime tree. This is usually done inside the AcRx::kInitAppMsg case of the acrxEntryPoint() switch statement (or a function called from there). This function needs to be called only once after all the rxInit() calls have been made.




    m_appServicePtr = acrxRegisterService(_T("ArxDbgServices"));


    ArxDbgAppEditorReactor::getInstance();
    MapTestReactor::getInstance();


registerDialogExtensions();
registerAppMenu();//注册右键菜单


endSplashScreen(splashScreen);


    m_didInit = true;
    return AcRx::kRetOK;
}


结束

AcRx::AppRetCode
ArxDbgApp::exitApp()
{
unRegisterAppMenu();


        // delete any of the notification spies that have been allocated
    ArxDbgUiTdmReactors::cleanUpReactors();
    ArxDbgAppEditorReactor::destroyInstance();
MapTestReactor::destroyInstance();


    if (m_didInit) {
        unRegisterCommands();
        unRegisterClasses();


        acutPrintf(_T("\n%s has been unloaded ... "), appName());
    }


    return AcRx::kRetOK;
}


猜你喜欢

转载自blog.csdn.net/jerryzfc/article/details/81036749
今日推荐