天天看点

ObjectARX中扩展记录和扩展字典

在ObjectARX二次开发中,如果想向图形的对象追加一些数据,可以使用扩展数据或者扩展记录,本文详细介绍这两种方法。

一 扩展数据

扩展数据(Extended data或者简称为xdata)可以添加到任何对象上,由一个结果缓冲区链表组成,链表的DXF组码范围为1000~1071。扩展数据适合给对象添加轻量化数据,数据总容量不能超过16KB.

设置扩展数据的函数为

请注意,结果缓冲区链表的第一个组码必须是1001,其后跟着一个字符串,这个字符串代表注册函数名称。因为任何一个应用程序都能将扩展数据附加到实体上,因此所有扩展数据都需要一个唯一的应用程序名称,该名称不超过31个字符,使用acdbRegApp函数进行注册。

以下代码可以给一个实体添加扩展数据。

void CmdAddEntXData()
{
	ads_name ent;
	AcGePoint3d ptPick;
	if (RTNORM == acedEntSel(_T("\n选择所要添加扩展数据的实体:"), ent, asDblArray(ptPick)))
	{
		CString appName = _XDATA_APPNAME_;

		// 注册应用程序名称
		acdbRegApp(appName);

		// 创建结果缓冲区链表
		struct resbuf* rb = acutBuildList(AcDb::kDxfRegAppName, appName,		// 应用程序名称
			AcDb::kDxfXdAsciiString, TEXT("字符串测试数据"),	// 字符串
			AcDb::kDxfXdInteger32, 2,							// 整数
			AcDb::kDxfXdReal, 3.14,								// 实数
			AcDb::kDxfXdWorldXCoord, asDblArray(ptPick),						// 点坐标值
			RTNONE);

		// 为选择的实体添加扩展数据
		AcDbEntity* pEnt;
		AcDbObjectId idEnt;
		acdbGetObjectId(idEnt, ent);
		if (Acad::eOk == acdbOpenObject(pEnt, idEnt, AcDb::kForWrite))
		{
			pEnt->setXData(rb);
			pEnt->close();
		}
		acutRelRb(rb);
		acutPrintf(TEXT("\n成功为实体添加了扩展数据."));
	}
}
           

对象的扩展数据是通过AcDbObject::xData函数获取的

如果regappName为 NULL,返回所有扩展数据。否则返回注册程序名称对应的扩展数据。

//打印所有扩展数据
void PrintXDataList(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 {// restype is already RTSHORT, RTSTR,...
			rt = pRb->restype; // or else it is unknown.
		}

		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);
		}
	}
}

//命令——查看实体的扩展数据
void CmdViewEntXData()
{
	ads_name ent;
	AcGePoint3d ptPick;
	if (RTNORM == acedEntSel(_T("\n选择所要添加扩展数据的实体:"), ent, asDblArray(ptPick)))
	{
		AcDbObjectId idEnt;
		AcDbEntity* pEnt;
		acdbGetObjectId(idEnt, ent);
		if (Acad::eOk == acdbOpenObject(pEnt, idEnt, AcDb::kForWrite))
		{
			CString appName = _XDATA_APPNAME_;

			// 获取实体的扩展数据
			struct resbuf *pRb = pEnt->xData(appName);
			if (pRb != NULL)
			{
				// 在命令行显示所有的扩展数据
				struct resbuf *pTemp = pRb;		// 使用临时的结果缓冲区指针进行遍历,pRb不修改便于释放
				PrintXDataList(pRb);
				acutRelRb(pRb);
			}
			else
				acutPrintf(_T("\n所选择的实体不包含任何的扩展数据!"));
			pEnt->close();
		}
	}
}
           

二 扩展记录

每一个对象(object)可以有一个扩展字典,扩展字典可以包含任意数量的AcDbObject对象。利用这个机制,多个程序可以将数据附加到对象上。扩展字典运行开销要高于扩展数据,但是它提供了更灵活的附加数据的机制。

实体在默认情况下不包含扩展字典,如果要利用扩展字典保存与实体关联的数据,可以使用AcDbObject::createExtensionDictionary函数为实体建立扩展字典。如果实体已经包含扩展字典,则该函数的调用不会产生任何影响。

创建扩展字典之后,就可以使用AcDbObject::extensionDictionary函数获得实体的扩展字典,AcDbDictionary对象的SetAt函数可以为字典添加一个元素,该元素既可以是AcDbXRecord,也可以是其他类型的对象。如果添加了AcDbXrecord,就可以使用acutBuildList函数构建一个保存数据的结果缓冲区链表,然后使用setFromRbChain函数将结果缓冲区链表添加到扩展记录中,这样就使用扩展记录保存了数据。

如果要访问实体扩展字典中保存的扩展记录,则可以使用对象的extensionDictionary函数获得实体的扩展字典,然后通过字典的getAt函数得到指定的元素(扩展记录),使用AcDbXrecord类的rbChain函数得到保存数据的结果缓冲区链表,从而可遍历该链表的所有数据。

以下代码给对象添加扩展记录。

#define _XRECORD_NAME_ _T("XRecord")

AcDbObjectId AddObjXRecord(AcDbObjectId idObj, const TCHAR* pszRecKey, const struct resbuf* pRb)
{
	if (!pRb)
		return AcDbObjectId::kNull;

	AcDbObjectId idDict;
	AcDbObject* pEnt;
	if (Acad::eOk == acdbOpenObject(pEnt, idObj, AcDb::kForWrite))
	{		
		pEnt->createExtensionDictionary();		//向实体添加扩展字典
		idDict = pEnt->extensionDictionary();
		pEnt->close();
	}
	else
		return AcDbObjectId::kNull;

	//创建扩展记录实体
	AcDbXrecord* pXRec = new AcDbXrecord;

	//向扩展字典中添加一条记录
	AcDbObjectId idXRecord = AcDbObjectId::kNull;
	AcDbDictionary* pDict = NULL;
	if (Acad::eOk == acdbOpenObject(pDict, idDict, AcDb::kForWrite))
	{
		pDict->setAt(pszRecKey, pXRec, idXRecord);
		pDict->close();
	}

	//设置扩展记录的内容
	pXRec->setFromRbChain(*pRb);
	pXRec->close();

	return idXRecord;
}

void CmdAddEntXRecord()
{
	//提示用户选择一个实体
	ads_name ent;
	AcGePoint3d ptPick;
	if (RTNORM != acedEntSel(_T("\n请选择一个实体"), ent, asDblArray(ptPick)))
		return;

	AcDbObjectId id;
	if (Acad::eOk == acdbGetObjectId(id, ent))
	{
		AcGePoint3d ptPick;
		struct resbuf* pRb = acutBuildList(AcDb::kDxfText, _T("测试字符串数据"),
			AcDb::kDxfInt32, 12,
			AcDb::kDxfReal, 3.14,
			AcDb::kDxfXCoord, asDblArray(ptPick),
			RTNONE);
		AddObjXRecord(id, _XRECORD_NAME_, pRb);
		acutRelRb(pRb);
	}
}
           

以下代码读取实体的扩展记录

//打印扩展记录链表
void printXRecordList(struct resbuf* pBuf)
{
	int rt, i;
	TCHAR buf[133];

	for (i = 0; pBuf != NULL; i++, pBuf = pBuf->rbnext) {
		if (pBuf->restype < 0)
			rt = pBuf->restype;
		else if (pBuf->restype < 10)
			rt = RTSTR;
		else if (pBuf->restype < 38)
			rt = RT3DPOINT;
		else if (pBuf->restype < 60)
			rt = RTREAL;
		else if (pBuf->restype < 80)
			rt = RTSHORT;
		else if (pBuf->restype < 100)
			rt = RTLONG;
		else if (pBuf->restype < 106)
			rt = RTSTR;
		else if (pBuf->restype < 148)
			rt = RTREAL;
		else if (pBuf->restype < 290)
			rt = RTSHORT;
		else if (pBuf->restype < 330)
			rt = RTSTR;
		else if (pBuf->restype < 370)
			rt = RTENAME;
		else if (pBuf->restype < 999)
			rt = RT3DPOINT;
		else
			rt = pBuf->restype;

		switch (rt) {
		case RTSHORT:
			if (pBuf->restype == RTSHORT)
				acutPrintf(_T("RTSHORT : %d\n"),
					pBuf->resval.rint);
			else
				acutPrintf(_T("(%d . %d)\n"), pBuf->restype,
					pBuf->resval.rint);
			break;
		case RTREAL:
			if (pBuf->restype == RTREAL)
				acutPrintf(_T("RTREAL : %0.3f\n"),
					pBuf->resval.rreal);
			else
				acutPrintf(_T("(%d . %0.3f)\n"), pBuf->restype,
					pBuf->resval.rreal);
			break;
		case RTSTR:
			if (pBuf->restype == RTSTR)
				acutPrintf(_T("RTSTR : %s\n"),
					pBuf->resval.rstring);
			else
				acutPrintf(_T("(%d . \"%s\")\n"), pBuf->restype,
					pBuf->resval.rstring);
			break;
		case RT3DPOINT:
			if (pBuf->restype == RT3DPOINT)
				acutPrintf(
					_T("RT3DPOINT : %0.3f, %0.3f, %0.3f\n"),
					pBuf->resval.rpoint[X],
					pBuf->resval.rpoint[Y],
					pBuf->resval.rpoint[Z]);
			else
				acutPrintf(
					_T("(%d %0.3f %0.3f %0.3f)\n"),
					pBuf->restype,
					pBuf->resval.rpoint[X],
					pBuf->resval.rpoint[Y],
					pBuf->resval.rpoint[Z]);
			break;
		case RTLONG:
			acutPrintf(_T("RTLONG : %dl\n"),
				pBuf->resval.rlong);
			break;
		case -1:
		case RTENAME:
			acutPrintf(_T("(%d . <Entity name: %8lx>)\n"),
				pBuf->restype, pBuf->resval.rlname[0]);
			break;
		case -3:
			acutPrintf(_T("(-3)\n"));
		}

		if ((i == 23) && (pBuf->rbnext != NULL)) {
			i = 0;
			acedGetString(0,
				_T("Press <ENTER> to continue..."), buf);
		}
	}
	return;
}

//获取实体扩展记录链表
BOOL GetObjXRecord(AcDbObjectId id, const TCHAR* pszRecKey, struct resbuf*& pRb)
{
	BOOL bRet = FALSE;
	AcDbObject* pEnt;
	if (Acad::eOk == acdbOpenObject(pEnt, id, AcDb::kForRead))
	{
		AcDbObjectId idExtensionDict = pEnt->extensionDictionary();
		pEnt->close();
		if (!idExtensionDict)
			return bRet;

		//打开扩展字典,获得与关键字pszRecKey关联的扩展记录
		AcDbDictionary* pDict = NULL;
		AcDbXrecord* pXRec = NULL;
		if (Acad::eOk == acdbOpenObject(pDict, idExtensionDict, AcDb::kForRead))
		{
			if (Acad::eOk == pDict->getAt(pszRecKey, (AcDbObject*&)pXRec, AcDb::kForRead))
			{
				pXRec->rbChain(&pRb);
				pXRec->close();
				bRet = TRUE;
			}
			pDict->close();
		}
	}
	return bRet;
}

void CmdViewEntXRecord()
{
	//提示用户选择一个实体
	ads_name ent;
	AcGePoint3d ptPick;
	if (RTNORM != acedEntSel(_T("\n请选择索要查看扩展记录的实体"), ent, asDblArray(ptPick)))
		return;

	//获得实体的扩展字典
	AcDbObjectId id;
	AcDbEntity* pEnt;
	acdbGetObjectId(id, ent);

	struct resbuf* pRb = NULL;
	if (GetObjXRecord(id, _XRECORD_NAME_, pRb))
	{
		printXRecordList(pRb);
		acutRelRb(pRb);
	}
	else
	{
		acutPrintf(_T("\n所选择实体不包含该扩展记录"));
	}
}
           

继续阅读