【CAD二次开发】-ObjectARX-扩展字典和有名对象字典(Xrecord)

思路:

(1)使用ObjectARX向导创建一个新工程Xrecord.

注册命令AddXRecord,提示用户选择一个实体,并将一些附加的数据保存到该实体的扩展字典中。

实现函数:

	static void AAAMyGroupAddRecord() {
		//提示用户选择所要添加扩展记录的图形对象
		AcDbEntity *pEnt = NULL;
		AcGePoint3d pickPoint;
		if (CSelectUtil::PromptSelectEntity(TEXT("\\n 选择所要添加扩展记录的实体"),
		AcDbEntity::desc(),pEnt,pickPoint))
		{
			//向实体中添加扩展字典
			pEnt->createExtensionDictionary();  //为实体建立扩展字典
			AcDbObjectId dictObjId = pEnt->extensionDictionary(); //获得
			                                 //实体的扩展字典
			pEnt->close();

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

			//向扩展字典中添加一条记录
			AcDbObjectId xRecObjId;
			AcDbDictionary *pDict = NULL;
			if (acdbOpenObject(pDict,dictObjId,AcDb::kForWrite) == Acad::eOk)
			{
				pDict->setAt(TEXT("XRecord"), pXrec, xRecObjId);
				pDict->close();
			}

			//设置扩展记录的内容
			struct resbuf* pRb = acutBuildList(AcDb::kDxfText, TEXT("测试字符串数据"),
				AcDb::kDxfInt32, 12,
				AcDb::kDxfReal, 3.14,
				AcDb::kDxfXCoord, asDblArray(pickPoint),
				RTNONE);
			pXrec->setFromRbChain(*pRb); //扩展数据内容填充扩展记录对象
			pXrec->close();
			acutRelRb(pRb);
		}

	}

代码段:pDict->setAt(TEXT("XRecord"), pXrec, xRecObjId);

  代码表示:如果"XRecord"还没有在字典中存在,那么这个函数就会在字典中添加新的条目,并将它添加到字典中。如果带有关键"XRecord"的条目已经存在,那么现有的条目将被删除,字典从它的反应堆列表中删除,并且它被新的值对象替换为它所处的字典。该对象的名称由"XRecord"指定。对象的objectId条目在 xRecObjId中返回。

"XRecord" 输入字符串表示对象的搜索键名
pXrec 输入指向新对象的指针以添加到字典中
xRecObjId 返回新添加对象的对象ID

其中,PromptSelectEntity函数的实现:

首先,创建一个类CSelectUtil,在此类中实现PromptSelectEntity。

函数的声明:

	// 提示用户选择某个类型的实体
	// 注意:调用者必须关闭实体	
	static bool PromptSelectEntity(const TCHAR* prompt, AcRxClass* classDesc, AcDbEntity *&pEnt, AcGePoint3d &pickPoint, 
		bool bOpenForWrite = true);
	static bool PromptSelectEntity(const TCHAR* prompt, const std::vector<AcRxClass*> &classDescs, AcDbEntity *&pEnt, 
		AcGePoint3d &pickPoint, bool bOpenForWrite = true);

函数的实现:

bool CSelectUtil::PromptSelectEntity( const TCHAR* prompt, AcRxClass* classDesc, AcDbEntity *&pEnt, 
									 AcGePoint3d &pickPoint, bool bOpenForWrite /*= true*/ )
{
	std::vector<AcRxClass*> descs;
	descs.push_back(classDesc);

	return PromptSelectEntity(prompt, descs, pEnt, pickPoint, bOpenForWrite);
}

bool CSelectUtil::PromptSelectEntity( const TCHAR* prompt, const std::vector<AcRxClass*> &classDescs, AcDbEntity *&pEnt, 
									 AcGePoint3d &pickPoint, bool bOpenForWrite /*= true*/ )
{
	ads_name ename;
RETRY:
	if (acedEntSel(prompt, ename, asDblArray(pickPoint)) != RTNORM)
	{
		pEnt = NULL;
		return false;
	}
	
	AcDbObjectId entId;
	acdbGetObjectId(entId, ename);
	
	// 判断选择的实体是否是指定类型的实体
	Acad::ErrorStatus es;
	if (bOpenForWrite)
	{
		es = acdbOpenObject(pEnt, entId, AcDb::kForWrite);
	}
	else
	{
		es = acdbOpenObject(pEnt, entId, AcDb::kForRead);
	}
	assert (es == Acad::eOk);
	bool bRet = false;
	for (int i = 0; i < (int)classDescs.size(); i++)
	{
		if (pEnt->isKindOf(classDescs[i]))
		{			
			bRet = true;
			break;
		}
	}
	
	if (bRet)
	{
		return true;
	}
	else
	{
		pEnt->close();
		acutPrintf(TEXT("\\n选择的实体类型不合要求, 请再次选择..."));
		goto RETRY;
	}
}

添加头文件:

#include <vector>

(2)注册新命令ViewXRecord,查看扩展字典中“XRecord”元素所保存的数据。

实现函数:

static void AAAMyGroupViewXRecord() {
		//提示用户选择所要查看扩展记录的图形对象
		AcDbEntity *pEnt = NULL;
		AcGePoint3d pickPoint;
		if (CSelectUtil::PromptSelectEntity(TEXT("\\n选择所要查看扩展记录的实体:"),
			AcDbEntity::desc(),pEnt,pickPoint))
		{
			//获得实体的扩展字典
			AcDbObjectId dictObjId = pEnt->extensionDictionary();
			pEnt->close();
			if (dictObjId.isNull())
			{
				acutPrintf(TEXT("\\n 所选择的实体不包含扩展字典!"));
				return;
			}
			//打开扩展字典,获得与关键字"XRecord"关联的扩展记录
			AcDbDictionary *pDict = NULL;
			AcDbXrecord *pXrec = NULL;
			struct resbuf *pRb = NULL;
			if (acdbOpenObject(pDict,dictObjId,AcDb::kForRead) == Acad::eOk)
			{
				pDict->getAt(TEXT("xRecord"), (AcDbObject*&)pXrec, AcDb::kForRead);

				//获得扩展记录的数据链表并关闭扩展数据对象
				pXrec->rbChain(&pRb);
				pXrec->close();

				pDict->close();
				
			}

			if (pRb != NULL)
			{
				//在命令行显示扩展记录内容
				struct resbuf *pTemp = pRb;

				acutPrintf(TEXT("\\n字符串类型的扩展数据是:%s"), pTemp->resval.rstring);

				pTemp = pTemp->rbnext;
				acutPrintf(TEXT("\\n整数类型的扩展数据是:%d"), pTemp->resval.rint);

				pTemp = pTemp->rbnext;
				acutPrintf(TEXT("\\n整数类型的扩展数据是:%.2f"), pTemp->resval.rreal);

				pTemp = pTemp->rbnext;
				acutPrintf(TEXT("\\n点坐标类型的扩展数据是:(%.2f,%.2f,%.2f)"),
					pTemp->resval.rpoint[X], pTemp->resval.rpoint[Y],
					pTemp->resval.rpoint[Z]);

				acutRelRb(pRb);
			}

		}

	}

(3)注册命令AddNameDict,向当前的图形数据库中添加一个字典,并在其中保存自定义数据。

实现函数为:

static void AAAMyGroupAddNameDict() {
		// 获得有名对象字典,向其中添加指定的字典项
		AcDbDictionary *pNameObjDict = NULL;
		acdbHostApplicationServices()->workingDatabase()
			->getNamedObjectsDictionary(pNameObjDict, 
				AcDb::kForWrite);

		//检查所要添加的字典项是否已经存在
		AcDbObjectId dictObjId;
		AcDbDictionary *pDict = NULL;
		if (pNameObjDict->getAt(TEXT("MyDict"), (AcDbObject*&)pDict,
			AcDb::kForWrite)
			== Acad::eKeyNotFound)
		{
			pDict = new AcDbDictionary;
			pNameObjDict->setAt(TEXT("MyDict"), pDict, dictObjId);
			pDict->close();
		}
		pNameObjDict->close();

		//向新建的字典中添加一个图层对象
		if (acdbOpenObject(pDict, dictObjId, AcDb::kForWrite) == Acad::eOk)
		{
			AcDbLayerTableRecord *pLayer = new AcDbLayerTableRecord();
			AcCmColor color;
			color.setColorIndex(20);
			pLayer->setColor(color);
			pLayer->setIsOff(true);
			pLayer->setIsFrozen(true);
			AcDbObjectId layerId;
			Acad::ErrorStatus es = pDict->setAt(TEXT("LayerKey"), pLayer, layerId);
			pLayer->close();
			pDict->close();
		}
	}

(4)注册一个新命令ViewNameDict,检查当前图形中是否包含指定的用户字典,并在命令窗口中显示字典中保存的自定义数据。

实现函数:

static void AAAMyGroupViewNameDict() {
		// 获得对象有名字典中指定的字典项
		AcDbDictionary *pNameObjDict = NULL;
		Acad::ErrorStatus es;
		acdbHostApplicationServices()->workingDatabase()
			->getNamedObjectsDictionary(pNameObjDict, AcDb::kForRead);
		AcDbDictionary *pDict = NULL;
		es = pNameObjDict->getAt(TEXT("MyDict"), (AcDbObject*&)pDict,
			AcDb::kForRead);
		pNameObjDict->close();

		//如果不存在指定的字典项,则退出程序
		if (es == Acad::eKeyNotFound)
		{
			acutPrintf(TEXT("\\n 不存在字典项MyDict."));
			return;
		}

		//获得指定的对象字典中的对象
		AcDbLayerTableRecord *pLayer = NULL;
		if (pDict->getAt(TEXT("LayerKey"), (AcDbObject*&)pLayer, AcDb::kForRead)
			== Acad::eOk)
		{
			//获得实体信息
			int colorIndex = pLayer->color().colorIndex();
			bool bOff = pLayer->isOff();
			bool bFrozen = pLayer->isFrozen();
			pLayer->close();

			//在命令行打印实体信息
			acutPrintf(TEXT("\\n 字典中的图层颜色: %d"), colorIndex);
			acutPrintf(TEXT("\\n 字典中的图层是否是关闭状态: %s"), bOff ?
				TEXT("是") : TEXT("否"));
			acutPrintf(TEXT("\\n 字典中的图层是否是冻结状态: %s"), bFrozen ?
				TEXT("是") : TEXT("否"));
		}
		pDict->close();

	}

 效果:

①在AutoCAD中加载应用程序,并执行AddXRecord,在图形窗口中选择一个实体,即可为图形添加扩展字典

②执行ViewXReocrd命令,查看扩展字典:

③利用ArxDbg工具查看:

 

⑥执行命令AddNameDict向图形的有名对象字典中添加用户字典。

⑦执命令ViewNameDict:

⑧ 使用ArxDbg也能观察有名对象字典的内容:

 

项目的完整源代码:

      https://pan.baidu.com/s/13Lj9mF_08oM26oqRlMnCxg

参考资料:

     张帆《AutoCAD ObjectARX(VC)开发基础与实例教程》

 

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片