在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所选择实体不包含该扩展记录"));
}
}