在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所選擇實體不包含該擴充記錄"));
}
}