Trang chủ

June 30, 2013

Sử dụng đối tượng phản ứng Object Reactor (phần 2)

Ví dụ: Xây dựng đối tượng phụ thuộc (Building in Object Dependencies )

Ví dụ dưới đây trình bầy cách để tạo ra các reactor để thiết lập các phụ thuộc (dependencies) giữa các đối tượng Cơ sở dữ liệu. Trong ví dụ này, khi bạn thay đổi một đoạn thẳng, đoạn thẳng kia cũng sẽ thay đổi theo.
class AsdkObjectToNotify : public AcDbObject
//
// AsdkObjectToNotify - customized AcDbObject for persistent
// reactor to notify.
//
{
public:
ACRX_DECLARE_MEMBERS(AsdkObjectToNotify);
AsdkObjectToNotify() {};
void eLinkage(AcDbObjectId i, double f=1.0)
{mId=i; mFactor=f; };
void modified(const AcDbObject*);
Acad::ErrorStatus dwgInFields(AcDbDwgFiler*);
Acad::ErrorStatus dwgOutFields(AcDbDwgFiler*) const;
Acad::ErrorStatus dxfInFields(AcDbDxfFiler*);
Acad::ErrorStatus dxfOutFields(AcDbDxfFiler*) const;
private:
AcDbObjectId mId;
double mFactor;
};
ACRX_DXF_DEFINE_MEMBERS(AsdkObjectToNotify, AcDbObject,
AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,
0, ASDKOBJECTTONOTIFY, persreac);
Hàm sau đây sẽ được gọi bất cứ khi nào đoạn thẳng (line) mà nó theo dõi được chỉnh sửa. Khi hàm được gọi tới, nó mở đoạn thẳng kia trong cặp đoạn thẳng và thay đổi chiều dài của đoạn thẳng đó.
// This function is called every time the line it's
// "watching" is modified. When it's called, it opens the
// other line of the pair and changes that line's length to
// match the new length of the line that's just been
// modified.
//
void
AsdkObjectToNotify::modified(const AcDbObject* pObj)
{
AcDbLine *pLine = AcDbLine::cast(pObj);

if (!pLine) {
const char* cstr = pObj->isA()->name();
acutPrintf("This is a %s.\n", cstr);
acutPrintf("I only work with lines. Sorry.\n");
return;
}

acutPrintf("\nReactor attached to %lx calling %lx.\n",
pLine->objectId(), mId);

// This open will fail during notification caused by a
// reactor being added to the entity or when this
// notification is in reaction to a change due to the
// other line's reactor changing this line. This will
// properly prevent an infinite recursive loop
// between the two lines and their reactors.
//
AcDbLine *pLine2;

if (acdbOpenObject((AcDbObject*&)pLine2, mId,
AcDb::kForWrite) == Acad::eOk)
{
// Get length of line entity we're being notified
// has just been modified.
//
AcGePoint3d p = pLine->startPoint();
AcGePoint3d q = pLine->endPoint();
AcGeVector3d v = q-p;
double len = v.length();

// update other entity to match:
//
p = pLine2->startPoint();
q = pLine2->endPoint();
v = q-p;
v = len * mFactor * v.normal();
pLine2->setEndPoint(p+v);
pLine2->close();
}
}

// Files an object's information in.
//
Acad::ErrorStatus
AsdkObjectToNotify::dwgInFields(AcDbDwgFiler* filer)
{
assertWriteEnabled();
AcDbObject::dwgInFields(filer);
filer->readItem(&mFactor);
filer->readItem((AcDbSoftPointerId*) &mId);
return filer->filerStatus();
}

// Files an object's information out.
//
Acad::ErrorStatus
AsdkObjectToNotify::dwgOutFields(AcDbDwgFiler* filer) const
{
assertReadEnabled();
AcDbObject::dwgOutFields(filer);
filer->writeItem(mFactor);
filer->writeItem((AcDbSoftPointerId&)mId);
return filer->filerStatus();
}

// Files an object's information in from DXF and AutoLISP.
//
Acad::ErrorStatus
AsdkObjectToNotify::dxfInFields(AcDbDxfFiler* filer)
{
assertWriteEnabled();
Acad::ErrorStatus es;
if ((es = AcDbObject::dxfInFields(filer))
!= Acad::eOk)
{
return es;
}

// Check if we're at the right subclass data marker.
//
if(!filer->atSubclassData("AsdkObjectToNotify")) {
return Acad::eBadDxfSequence;
}

struct resbuf rbIn;

while (es == Acad::eOk) {
if ((es = filer->readItem(&rbIn)) == Acad::eOk) {
if (rbIn.restype == AcDb::kDxfReal) {
mFactor = rbIn.resval.rreal;
} else if (rbIn.restype
== AcDb::kDxfSoftPointerId)
{
// ObjectIds are filed in as ads_names.
//
acdbGetObjectId(mId, rbIn.resval.rlname);
} else { // invalid group
return(filer->pushBackItem());
}
}
}
return filer->filerStatus();
}

// Files an object's information out to DXF and AutoLISP.
//
Acad::ErrorStatus
AsdkObjectToNotify::dxfOutFields(AcDbDxfFiler* filer) const
{
assertReadEnabled();
AcDbObject::dxfOutFields(filer);
filer->writeItem(AcDb::kDxfSubclass,
"AsdkObjectToNotify");
filer->writeItem(AcDb::kDxfReal, mFactor);
filer->writeItem(AcDb::kDxfSoftPointerId, mId);
return filer->filerStatus();
}
Tạo ra hai đoạn thẳng và hai đối tượng AsdkObjectToNotify và ràng buộc (tie) chúng lại với nhau

// Creates two lines and two AsdkObjectToNotify objects and
// ties them all together.
//
void
assocLines()
{
AcDbDatabase *pDb =
acdbHostApplicationServices()->workingDatabase();
AcDbObjectId aId, bId;
AcDbLine *pLineA = new AcDbLine;
pLineA->setDatabaseDefaults(pDb);
pLineA->setStartPoint(AcGePoint3d(1, 1, 0));
pLineA->setEndPoint(AcGePoint3d(2, 1, 0));
addToModelSpace(aId, pLineA);

acutPrintf( "Line A is %lx from 1,1 to 2,1.\n",
pLineA->objectId());
AcDbLine *pLineB = new AcDbLine;
pLineB->setDatabaseDefaults(pDb);
pLineB->setStartPoint(AcGePoint3d(1, 2, 0));
pLineB->setEndPoint(AcGePoint3d(2, 2, 0));
addToModelSpace(bId, pLineB);
acutPrintf("Line B is %lx from 1,2 to 2,2.\n",
pLineB->objectId());
// Open the named object dictionary, and check if there is
// an entry with the key "ASDK_DICT". If not, create a
// dictionary and add it.
//
AcDbDictionary *pNamedObj;
AcDbDictionary *pNameList;
pDb->getNamedObjectsDictionary(pNamedObj,
AcDb::kForWrite);

if (pNamedObj->getAt("ASDK_DICT",
(AcDbObject*&)pNameList, AcDb::kForWrite)
== Acad::eKeyNotFound)
{
pNameList = new AcDbDictionary;
AcDbObjectId DictId;
pNamedObj->setAt("ASDK_DICT", pNameList, DictId);
}

pNamedObj->close();

// Create the AsdkObjectToNotify for line A.
//
AsdkObjectToNotify *pObj = new AsdkObjectToNotify();
pObj->eLinkage(bId);
AcDbObjectId objId;

if ((pNameList->getAt("object_to_notify_A", objId))
== Acad::eKeyNotFound)
{
pNameList->setAt("object_to_notify_A", pObj, objId);
pObj->close();
} else {
delete pObj;
acutPrintf("object_to_notify_A already exists\n");
}

// Set up persistent reactor link between line A
// and AsdkObjectToNotify.
//
pLineA->addPersistentReactor(objId);
pLineA->close();

// Create the AsdkObjectToNotify for line B.
//
pObj = new AsdkObjectToNotify();
pObj->eLinkage(aId);

if ((pNameList->getAt("object_to_notify_B", objId))
== Acad::eKeyNotFound)
{
pNameList->setAt("object_to_notify_B", pObj, objId);
pObj->close();
} else {
delete pObj;
acutPrintf("object_to_notify_B already exists\n");
}
pNameList->close();

// Set up persistent reactor link between line B
// and AsdkObjectToNotify.
//
pLineB->addPersistentReactor(objId);
pLineB->close();
}
Thêm thực thể vào không gian model, nhưng không đóng thực thể lại.

// Adds an entity to model space, but does not close
// the entity.
//
void
addToModelSpace(AcDbObjectId &objId, AcDbEntity* pEntity)
{
AcDbBlockTable *pBlockTable;
AcDbBlockTableRecord *pSpaceRecord;
acdbHostApplicationServices()->workingDatabase()
->getSymbolTable(pBlockTable, AcDb::kForRead);
pBlockTable->getAt(ACDB_MODEL_SPACE, pSpaceRecord,
AcDb::kForWrite);
pBlockTable->close();
pSpaceRecord->appendAcDbEntity(objId, pEntity);
pSpaceRecord->close();
return;
}
Các hàm khởi động và kết thúc quá trình làm việc.
// This is the initialization function called from acrxEntryPoint()
// during the kInitAppMsg case. This function is used to add
// commands to the command stack.
//
void
initApp()
{
acedRegCmds->addCommand("ASDK_ALINES", "ASDK_ALINES",
"ALINES", ACRX_CMD_MODAL, assocLines);
AsdkObjectToNotify::rxInit();
acrxBuildClassHierarchy();
}

// This is the clean-up function called from acrxEntryPoint() during
// the kUnloadAppMsg case. This function removes this application's
// command set from the command stack.
//
void
unloadApp()
{
acedRegCmds->removeGroup("ASDK_ALINES");

// Remove the AsdkObjectToNotify class from the ACRX
// runtime class hierarchy. If this is done while the
// database is still active, it should cause all objects
// of class AsdkObjectToNotify to be turned into proxies.
//
deleteAcRxClass(AsdkObjectToNotify::desc());
}

// ObjectARX entry point
//
extern "C" AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
switch (msg) {
case AcRx::kInitAppMsg:
acrxDynamicLinker->unlockApplication(appId);
acrxDynamicLinker->registerAppMDIAware(appId);
initApp();
break;
case AcRx::kUnloadAppMsg:
unloadApp();
}
return AcRx::kRetOK;
}

No comments:

Post a Comment