Sử dụng Editor Reactor
Lớp AcEditorReactor cung cấp nhiều hàm để phản ứng lại với rất nhiều loại sự kiện. Một trong số đó là beginClose(), beginDxfIn(), dxfInComplete(), beginSave(), và saveComplete(). Không một tương tác AutoLISP® có thể tiến hành trong một chức năng thông báo (Thật tuyệt vời - mình đã lựa chọn đúng).
Theo dõi chính xác việc tạo bản vẽ mới, Open và Close
Một kỹ thuật hấp dẫn để theo dõi việc người dùng tạo mới, mở hoặc đóng một bản vẽ là giành quyền của phương thức AcEditorReactor::commandWillStart() và commandEnded(), và tìm chuỗi ký tự "OPEN", "NEW", "QUIT", và "CLOSE". Việc làm này rất dễ bị lỗi, bởi vì bản vẽ cũng có thể được mở bởi các ứng dụng khác, ví dụ như là một lệnh riêng, MFC, OLE và DDE.... Trong trường hợp này, phản hồi sẽ xảy ra và được gửi đến trình xử lý sự kiện của Windows mà không phải bộ xử lý của AutoCAD.
Một phương tiện theo dõi quá trình an toàn hơn là giành quyền các reactor phản hồi (reactor callbacks), được gắn trực tiếp vào bản vẽ (document) hoặc sự kiện CSDL, hơn là sự kiện của command. Danh sách dưới đây thể hiện các reactor phản hồi mà bạn nên xem xét sử dụng thay cho phương thức AcEditorReactor::commandWillStart() và commandEnded().
Với một bản vẽ (được chỉnh sửa) new, open, và close:
- AcApDocManagerReactor::documentCreated()
- AcApDocManagerReactor::documentToBeDestroyed()
- AcApDocManagerReactor::documentDestroyed()
- AcApDocManagerReactor::documentCreateStarted()
- AcApDocManagerReactor::documentCreateCanceled()
Với việc CSDL được tạo, mở hoặc đóng:
- AcEditorReactor::beginDwgOpen()
- AcEditorReactor::endDwgOpen()
- AcRxEventReactor::dwgFileOpened()
- AcRxEventReactor::databaseConstructed()
- AcRxEventReactor::databaseToBeDestroyed()
Xem thêm tài liệu tham chiếu ObjectARX sẽ giúp quyết định loại phản hồi (callback) nào là thích hợp nhất cho ứng dụng của bạn
Using a Database Reactor
Ví dụ dưới đây sử dụng một reactor dẫn xuất từ AcDbDatabaseReactor để theo dõi có bao nhiêu đối tượng xuất hiện trong CSDL. Nó thực thi 3 hàm thông báo cho đối tượng reactor: objectAppended(), objectModified(), và objectErased(). Hàm watch_db() thêm reactor vào trong CSDL hiện tại. Hàm clear_reactors() loại bỏ reactor từ CSDL và xóa reactor CSDL.
class AsdkDbReactor;
long gEntAcc = 0; // Global entity count
AsdkDbReactor *gpDbr = NULL; // Pointer to database reactor
// Custom AcDbDatabaseReactor class for database
// event notification.
//
class AsdkDbReactor : public AcDbDatabaseReactor
{
public:
virtual void objectAppended(const AcDbDatabase* dwg,
const AcDbObject* dbObj);
virtual void objectModified(const AcDbDatabase* dwg,
const AcDbObject* dbObj);
virtual void objectErased(const AcDbDatabase* dwg,
const AcDbObject* dbObj, Adesk::Boolean pErased);
};
// Called whenever an object is added to the database.
//
void
AsdkDbReactor::objectAppended(const AcDbDatabase* db,
const AcDbObject* pObj)
{
printDbEvent(pObj, "objectAppended");
acutPrintf(" Db==%lx\n", (long) db);
gEntAcc++;
acutPrintf("Entity Count = %d\n", gEntAcc);
}
// Called whenever an object in the database is modified.
//
void
AsdkDbReactor::objectModified(const AcDbDatabase* db,
const AcDbObject* pObj)
{
printDbEvent(pObj, "objectModified");
acutPrintf(" Db==%lx\n", (long) db);
}
// Called whenever an object is erased from the database.
//
void
AsdkDbReactor::objectErased(const AcDbDatabase* db,
const AcDbObject* pObj, Adesk::Boolean pErased)
{
if (pErased) {
printDbEvent(pObj, "objectErased");
gEntAcc--;
} else {
printDbEvent(pObj, "object(Un)erased");
gEntAcc++;
}
acutPrintf(" Db==%lx\n", (long) db);
acutPrintf("Entity Count = %d\n", gEntAcc);
}
// Prints the message passed in by pEvent; then
// calls printObj() to print the information about
// the object that triggered the notification.
//
void
printDbEvent(const AcDbObject* pObj, const char* pEvent)
{
acutPrintf(" Event: AcDbDatabaseReactor::%s ", pEvent);
printObj(pObj);
}
// Prints out the basic information about the object pointed
// to by pObj.
//
void
printObj(const AcDbObject* pObj)
{
if (pObj == NULL) {
acutPrintf("(NULL)");
return;
}
AcDbHandle objHand;
char handbuf[17];
// Get the handle as a string.
//
pObj->getAcDbHandle(objHand);
objHand.getIntoAsciiBuffer(handbuf);
acutPrintf(
"\n (class==%s, handle==%s, id==%lx, db==%lx)",
pObj->isA()->name(), handbuf,
pObj->objectId().asOldId(), pObj->database());
}
// Adds a reactor to the database to monitor changes.
// This can be called multiple times without any ill
// effect because subsequent calls will be ignored.
//
void
watchDb()
{
if (gpDbr == NULL) {
gpDbr = new AsdkDbReactor();
}
acdbHostApplicationServices()->workingDatabase()->addReactor(
gpDbr);
acutPrintf(
" Added Database Reactor to "
"acdbHostApplicationServices()->workingDatabase().\n");
}
// Removes the database reactor.
//
void
clearReactors()
{
if (acdbHostApplicationServices()->workingDatabase() != NULL) {
acdbHostApplicationServices()->workingDatabase(
)->removeReactor(gpDbr);
delete gpDbr;
gpDbr = NULL;
}
}
// ObjectARX entry point function
//
extern "C" AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
switch (msg) {
case AcRx::kInitAppMsg:
acrxDynamicLinker->unlockApplication(appId);
acrxDynamicLinker->registerAppNotMDIAware(appId);
acedRegCmds->addCommand("ASDK_NOTIFY_TEST",
"ASDK_WATCH",
"WATCH",
ACRX_CMD_TRANSPARENT,
watchDb);
acedRegCmds->addCommand("ASDK_NOTIFY_TEST",
"ASDK_CLEAR",
"CLEAR",
ACRX_CMD_TRANSPARENT,
clearReactors);
break;
case AcRx::kUnloadAppMsg:
clearReactors();
acedRegCmds->removeGroup("ASDK_NOTIFY_TEST");
break;
}
return AcRx::kRetOK;
}
.
No comments:
Post a Comment