1.自定义数据
ObjectARX开发过程中,有时会使用自定义数据,主要包括:
- 自定义对象——可以让用户按照自己希望的方式封装数据,并向AutoCAD中添加第三方实体类型,这些实体类型用于与AutoCAD自身实体一样的特性,ObjectARX程序能够灵活控制自定义实体的显示。
- 扩充数据——可以向图形本身或者图形中的实体追加一些数据。
扩充数据又分为Xdata(eXtension data)和 Xrecord(eXtension record)两种。
2.Xdata
- AutoCAD数据库的任何对象都可以灵活的附加一定数量的扩展数(Xdata),供开发者使用。
- 扩展数据的含义由开发者自行解释,AutoCAD只维护这些数据而不管其具体的含义。
- 扩展数据是链表组,每个组是链表系列,以一个名字开头以做标识。这个名字是应用程序名。
- 应用程序名通过acdbRegApp()进行注册,最长可达31个字符 所附着的数据链表不能超过16K。
- DXF组码只能采用1000~1071之间的组码值。
2.1 Xdata相关函数—acdbRegApp
定义:
int acdbRegApp(const ACHAR * appname
);
作用:在当前图形中注册一个应用程序名称,用于分组,存储,检索和修改实体的扩展数据。appname必须遵守符号表名称(例如图层名称)的规则,且不能和已经存在的RegApp重复。每个新名称将产生一个新的acdbRegApp记录。
返回值:
- appname注册成功,返回RTNORM;
- appname已存在,返回RTERROR;
- appname注册失败,返回一个表明失败原因的系统变量ERRNO。
2.2 Xdata相关函数—setXData
定义:
virtual Acad::ErrorStatus setXData(const resbuf* xdata
);
作用:设置一个对象的扩展数据。
- 每个注册(regappname)链表以 restype = 1001 分界,并且resval.rstring应该是合法字符。
- RegappName必须是AcDbRegAppTable中存在的。
- 如果xdata中已经有该regappname组, 则新的链表将覆盖之 。
- 要清除xdata中某个regappname的所有内容,只需建立一个以此regappname开头的空链表即可。
返回值:
- 如果xdata成功添加到对象,则返回Acad :: eOk。
- 如果对象的xdata区域中没有足够的空间,则返回Acad::eXdataSizeExceeded。
- 如果xdata中的所有regappName均不存在,则返回Acad :: eRegappIdNotFound。
2.3 Xdata相关函数—XData
定义:
virtual resbuf* xData(const ACHAR* regappName = nullptr
) const;
作用:获取一个对象中名为“regappName”的扩展数据。如果regappName == NULL,则返回所有xdata,否则仅返回指定名称为regappName的xdata。如果需要多个regappName的xdata,则必须对该成员函数进行多次调用,每个regappName调用一次。
返回值:
- 返回包含对象xdata副本的resbuf结构的链接列表。
2.4 Xdata实例,添加、查看和删除Xdata
添加Xdata代码如下:
//添加Xdatastatic void MyGroupaddXdata() {//提示用户选择对象AcDbObject* pObj = selectObject(AcDb::kForRead);if (!pObj) {acutPrintf(_T("Error selecting object\n"));return;}//获取Xdata名称TCHAR appName[132], resString[200];appName[0] = resString[0] = _T('\0');acedGetString(NULL, _T("Enter application name: "), appName);acedGetString(NULL, _T("Enter string to be added: "), resString);struct resbuf *pRb, *pTemp;pRb = pObj->xData(appName);if (pRb != NULL) {//如果Xdata已经存在,不执行任何操作for (pTemp = pRb; pTemp->rbnext != NULL;pTemp = pTemp->rbnext){ ; }} else {//如果Xdata不存在,向当前对象注册名为appName的XdataacdbRegApp(appName);pRb = acutNewRb(AcDb::kDxfRegAppName);pTemp = pRb;pTemp->resval.rstring= (TCHAR*) malloc((_tcslen(appName) + 1) * sizeof(TCHAR));_tcscpy(pTemp->resval.rstring, appName);}//向新注册的Xdata添加自定义扩展数据pTemp->rbnext = acutNewRb(AcDb::kDxfXdAsciiString);pTemp = pTemp->rbnext;pTemp->resval.rstring= (TCHAR*) malloc((_tcslen(resString) + 1) * sizeof(TCHAR));_tcscpy(pTemp->resval.rstring, resString);//把对象从AcDb::kForRead 状态变成AcDb::kForWrite状态pObj->upgradeOpen();pObj->setXData(pRb);pObj->close();acutRelRb(pRb);}
查看Xdata代码如下:
//显示Xdata
static void MyGroupprintXdata(){//提示用户选择对象AcDbObject *pObj;if ((pObj = selectObject(AcDb::kForRead)) == NULL) {return;}//获取Xdata名称TCHAR appname[133];if (acedGetString(NULL,_T("\nEnter the desired Xdata application name: "),appname) != RTNORM){return;}// 根据Xdata名称appname,调用printList()函数输出Xdata信息struct resbuf *pRb;pRb = pObj->xData(appname);if (pRb != NULL) {printList(pRb);acutRelRb(pRb);} else {acutPrintf(_T("\nNo xdata for this appname"));}pObj->close();}
删除Xdata代码如下:
//删除Xdatastatic void MyGroupdeleteXdata(){AcDbObject* pObj = selectObject(AcDb::kForRead);if (!pObj) {acutPrintf(_T("Error selecting object\n"));return;}//获取Xdata名称 TCHAR appName[132];appName[0] = _T('\0');acedGetString(NULL, _T("Enter application name: "), appName);//在pObj的Xdata中查找appNamestruct resbuf *pTemp = nullptr; pTemp = pObj -> xData(appName);if (pTemp != nullptr){// 删除名为appName的XdataacdbRegApp(appName);struct resbuf* pRb = acutBuildList(AcDb::kDxfRegAppName, appName, RTNONE);pObj->upgradeOpen();pObj->setXData(pRb);acutRelRb(pRb);acutPrintf(TEXT("\nXdata deleted successfully."));}else{//未找到需要删除的XdataacutPrintf(TEXT("\nNo Xdata found."));}acutRelRb(pTemp);pObj->close();}
还需要添加两个函数,printList()用于在命令窗口中打印Xdata信息;selectObject()用于提示用户选择实体。代码如下:
//在AutoCAD命令窗口中打印Xdata信息static void printList(struct resbuf* pRb){int rt, i;TCHAR buf[133];for (i = 0;pRb != NULL;i++, pRb = pRb->rbnext) {if (pRb->restype < 1010) {rt = RTSTR;} else if (pRb->restype < 1040) {rt = RT3DPOINT;} else if (pRb->restype < 1060) {rt = RTREAL;} else if (pRb->restype < 1071) {rt = RTSHORT;} else if (pRb->restype == 1071) {rt = RTLONG;} else {rt = pRb->restype; }switch (rt) {case RTSHORT:if (pRb->restype == RTSHORT) {acutPrintf(_T("RTSHORT : %d\n"), pRb->resval.rint);} else {acutPrintf(_T("(%d . %d)\n"), pRb->restype,pRb->resval.rint);};break;case RTREAL:if (pRb->restype == RTREAL) {acutPrintf(_T("RTREAL : %0.3f\n"),pRb->resval.rreal);} else {acutPrintf(_T("(%d . %0.3f)\n"), pRb->restype,pRb->resval.rreal);};break;case RTSTR:if (pRb->restype == RTSTR) {acutPrintf(_T("RTSTR : %s\n"),pRb->resval.rstring);} else {acutPrintf(_T("(%d . \"%s\")\n"), pRb->restype,pRb->resval.rstring);};break;case RT3DPOINT:if (pRb->restype == RT3DPOINT) {acutPrintf(_T("RT3DPOINT : %0.3f, %0.3f, %0.3f\n"),pRb->resval.rpoint[X],pRb->resval.rpoint[Y],pRb->resval.rpoint[Z]);} else {acutPrintf(_T("(%d %0.3f %0.3f %0.3f)\n"),pRb->restype,pRb->resval.rpoint[X],pRb->resval.rpoint[Y],pRb->resval.rpoint[Z]);}break;case RTLONG:acutPrintf(_T("RTLONG : %dl\n"), pRb->resval.rlong);break;}if ((i == 23) && (pRb->rbnext != NULL)){i = 0;acedGetString(0,_T("Press <ENTER> to continue..."), buf);}}}//提示用户选择实体static AcDbObject* selectObject(AcDb::OpenMode openMode){int ss;ads_name en;ads_point pt;acedInitGet(RSG_OTHER, _T("Handle _Handle"));ss = acedEntSel(_T("\nSelect an Entity or enter")_T(" 'H' to enter its handle: "), en, pt);TCHAR handleStr[132];AcDbObjectId eId;switch (ss) {case RTNORM: break;case RTKWORD:if ((acedGetString(Adesk::kFalse,_T("Enter Valid Object Handle: "),handleStr) == RTNORM)&& (acdbHandEnt(handleStr, en) == RTNORM)){break;}default:acutPrintf(_T("Nothing Selected, Return Code==%d\n"),ss);return NULL;}Acad::ErrorStatus retStat;retStat = acdbGetObjectId(eId, en);if (retStat != Acad::eOk) {acutPrintf(_T("\nacdbGetObjectId failed"));acutPrintf(_T("\nen==(%lx,%lx), retStat==%d\n"),en[0], en[1], eId);return NULL;}AcDbObject* obj;if ((retStat = acdbOpenObject(obj, eId, openMode))!= Acad::eOk){acutPrintf(_T("acdbOpenEntity failed: ename:(%lx,%lx),")_T(" mode:%d retStat:%d"), en[0], en[1],openMode, retStat);return NULL;}return obj;}
3.代码效果
使用“addXdata”命令选择实体并添加扩展数据,“printXdata”命令在AutoCAD的命令窗口显示添加的扩展数据,“deleteXdata”命令删除扩展数据。如下图所示,使用Xdata向图中被选中直线追加了自定义数据。

4.源代码
源代码:xData
提取码:4bbm
参考文档
[1]:Autodesk ObjectARX for AutoCAD 2015: Developer Guide.

















