V tejto sekcii cvičení učebnice ObjectARX 2000, sa pozrieme na prechodné reaktory (Transient Reactors). Reaktory sú umiestnené v prostredí AutoCADu na sledovanie a reagovanie na udalosti, ktoré v AutoCADe nastanú. Reaktory majú mnoho typov. V tomto kroku sa pozrieme na päť typov reaktorov, a to: databázový reaktor (AcDbDatabaseReactor); reaktor AutoCAD editora (AcDbEditorReactor); reaktor objektov (AcDbObjectReactor); a reaktor manažéra dokumentov AutoCADu (AcApDocManagerReactor). Databázový reaktor (AcDbDatabaseReactor) monitoruje databázu AutoCADu a vie reagovať na udalosti ako pridanie alebo odobratie entít do a z databázy. Reaktor editora (AcDbEditorReactor) monitoruje editor AutoCADu a vie reagovať na rôzne práve spustené príkazy AutoCADu. Reaktor objektov (AcDbObjectReactor) vie (napr.) monitorovať udalosti na špecifickej entite, ako je zmena vlastností entity. A nakoniec AutoCAD 2000 má viacdokumentové prostredie a reaktor dokumentov (AcApDocManagerReactor) vie monitorovať udalosti ako prepnutie z jedného výkresu na druhý a môže byť použitý na spravovanie globálnych dát výkresov.
Táto aplikácia neregistruje žiadny nový príkaz AutoCADu, je založená na inštanciách referencie bloku EMPLOYEE ktorý bol vyvinutý v Kroku 3. Bude potrebné vložiť referencie bloku EMPLOYEE do výkresu AutoCADu. Kedykoľvek sa používatel pokúsi presunúť referenciu bloku EMPLOYEE program prestaví referenciu bloku EMPLOYEE na jej predošlú pozíciu. Tu je implementovaná stratégia v použití reaktoru editora, ktorý bude upozornený keď nejaký príkaz AutoCADu zmení umiestnenie referencie bloku EMPLOYEE. Keď bude aplikovaný nejaký z editovacích príkazov na presunutie referencie bloku EMPLOYEE, potom bude zaznamenaná pôvodná a konečná pozícia referencie bloku EMPLOYEE.
Na dosiahnutie tohoto, reaktor objektu je plánovaný pre každú referenciu bloku tak aby detegoval, keď bude referencia bloku EMPLOYEE otvorená pre operáciu modifikácie. To nastane predtým ako sa aktuálna transformácia uskutoční. Na detegovanie novej pozície pre referenciu bloku po uskutočnení transformácie, potrebujeme implementovať upozornenie reaktora editora pre 'command ended'.
Na koniec, potrebujeme detegovať vytváranie nových referencií bloku EMPLOYEE, to dosiahneme reaktorom databázy.
Zober na vedomie, že používatel sa môže rozhodnúť aplikovať editovacie príkazy na označenú skupinu, ktorá môže obsahovať jednu alebo viac referencií bloku EMPLOYEE spolu s inými typmi entít. Na ošetrenie takéhoto prípadu, potrebujeme použiť pole ID čísiel práve modifikovaných objektov (AcDbObjectIdArray) referencií blokov EMPLOYEE. Paralelne k tomu, tiež potrebujeme udržiavať pole bodov (AGePoint3dArray) na uloženie zodpovedajúcich originálnych pozícií referencií blokov EMPLOYEE.
Na podporu správy AcDbObjectIdArray a AcGePoint3dArray, potrebujeme spravovať tieto dáta na úrovni dokumentov. Každý dokument bude spravovať svoju vlastnú zostavu AcDbObjectIdArray a AcGePoint3dArray dát. Preto potrebujeme reaktor manažéra dokumentov na správu patričnej zostavy dát keď sa zmení (prepne) aktívny dokument.
- Zaveď projekt "Krok03", ktroý vytvoril ObjectARX Wizard alebo pokračuj so súbormi ktoré si vytvoril v predchádzajúcom kroku.
- Priprav dáta dokumentu.
- Pridaj a implementuj reaktor editora pre aplikáciu.
- Pridaj a implementuj reaktor objektu pre aplikáciu.
- Implementuj používateľom definovanú funkciu 'attachEmployeeReactorToAllEmployee()'
- Implementuj používateľom definovanú funkciu 'detachAllEmployeeReactors()'
- Pridaj a implementuj reaktor databázy pre aplikáciu.
- Testuj aplikáciu.
Priprav dáta dokumentu
ObjectARX Wizard automaticky vytvára triedu CDocData (pozri DocData.h, DocData.cpp a AsdkDMgr.h). Trieda CDocData sa mmôže použiť na implementovanie dát závislých na dokumente. Ak pokračuješ z predchádzajúceho kroku, over si že aplikácia "Project" je aktívnym projektom vo Visual C++.
- Pridaj členské premenné vypísané v nasledujúcej tabuľke do triedy CDocData v súbore DocData.h:
Členské premenné na pridanie do triedyCDocData Dátový typ Meno premennej bool m_editCommand bool m_doRepositioning AcDbObjectIdArray m_changedObjects AcGePoint3dArray m_employeePositions
- m_editCommand sa použie na zaznamenanie, či je aktívny niektorý z našich monitorovaných editovacích príkazov.
- m_doRepositioning sa použije na zistenie, či je potrebné dať na miesto nejakú referenciu bloku EMPLOYEE, takže môžeme ignorovať/monitorovať spätné volania reaktora.
- m_changedObjects sa použije na zaznamenanie, ktoré referencie blokov EMPLOYEE budú modifikované.
- m_employeePositions sa použie na uloženie originálnej pozície referencií bloku EMPLOYEE.
- V konštruktore pre CDocData v CDocData.cpp inicualizujeme
m_editCommand = false; m_doRepositioning = false;Pozn.: Prístup k dátam závislým na dokumente je dosiahnutý prostredníctvom DocVars.docData(). Pre detaily pozri deklaráciu globálnej premennej AsdkDataManager DocVars v CDocData.cpp.
Pridaj a implementuj reaktor aditora pre aplikáciu
- Použi nástrojový panel ObjectARX Wizard (pozri Krok 7 Obr. 1) na vytvornie triedy reaktora editora AsdkEdEmployeeReactor odvodeného z AcEditorReactor. Wizard automaticky prefixuje triedu symbolom RDS.
![]()
Krok 7 Obr. 1 - Výber prechodných reaktorov z nástrojového panela ObjectARX- Použitím ObjectARX Wizard pridaj funkciu commandWillStart() a commandEnded().
Pozn.: Over si, že ObjectARX aplikácia je aktívnym projektom vo Visual C++ a nie nejaká ObjectDBX aplikácia. ObjectDBX aplikácia nepodporujú AcEditorReactor a preto neuvidíš tento typ reaktora v zozname.
![]()
Krok 7 Obr. 2 - Pridanie funkcií prechodného reaktora- Pridaj kód do commandWillStart() ktorý dokáže nasledovné :
- Skontroluj či je spustený niektorý z príkazov "MOVE", "ROTATE", "STRETCH", "SCALE" alebo "GRIP_STRETCH" (použi funkciu na porovnávanie reťazcov ako je strcmp() práve použitý príkaz je odovzdaný prostredníctvom parametra).
- Ak je to jeden z monitorovaných príkazov, nastav m_editCommand = true; a m_doRepositioning = false; (Použi DocVars.docData().<patričnú premennú sem>).
- Znova nastav ID čísla objektov a informácie o pozícii (AcDbObjectIdArray::setLogicalLength()) na nulu.
- Pridaj kód do commandEnded() ktorý dokáže nasledovné:
- Ak práve monitorovaný príkaz nepatrí k monitorovaným príkazom zo zoznamu príkazov vyššie, potom nastav m_editCommand = false; a jednoducho sa vráť.
- Nastav m_editCommand na false.
- Nastav m_doRepositioning na true a spusti premiestnenie presunutých objektov na pôvodné miesto
- Pre každý objekt v m_changedObjects (AcDbObjectIdArray::length()) urob nasledovné:
- Otvor entitu (acdbOpenObject()).
- Ak sa aktuálna pozícia líši od uloženej pozície, obnov pozíciu objektu (AcDbBlockReference::position(), m_employeePositions.at(), AcDbBlockReference::setPosition())
- Vytvor inštanciu reaktora AsdkEdEmployeeReactor.
- Vytvor globálny ukazovatel na svoj reaktor editora. Umiestni tento reaktor v súbore "Project.cpp" nasledovne:
AsdkEdEmployeeReactor *pEdEmployeeReactor = NULL;- Vytvor inštanciu AsdkEdEmployeeReactor reaktora editora keď sa zavedie aplikácia, umiestni to do 'InitApplication()' v súbore "Project.cpp".
pEdEmployeeReactor = new AsdkEdEmployeeReactor(true);Pozn.: Obyčajne pri práci s prechodnými reaktormi používame funkcie 'addReactor()' a 'removeReactor()' na umiestnenie/odobratie našich prechodných reaktorov v správnom čase počas behu našej aplikácie. V tomto konkrétnom prípade trieda AsdkEdEmployeeReactor bola vygenerovaná "sprievodcom" ObjectARX Wizard, ktorý preberal zodpovednosť za pridanie/odobratie AsdkEdEmployeeReactor do konštruktora/deštruktora triedy. Pozri "rEditorReactor.cpp" pre detaily. Teda reaktor editora je pridaný iba pri zavedení našej aplikácie a odstránený pri uvolnení našej aplikácie. Je veľmi dôležité odstrániť náš reaktor editora pri uvolňovaní aplikácie. Neurobenie tohoto môže spôsobiť zrútenie AutoCADu. Je to tvoja povinnosť.
- Pri uvolňovaní aplikácie vymaž rektor editora. Umiestni nasledové do 'UnloadApplication()':
delete pEdEmployeeReactor;
Pridaj a implementuj reaktor objektu pre aplikáciu
- Použi ObjectARX Wizard na vytvorenie triedy AsdkEmployeeReactor reaktora objektu odvodenej z AcDbObjectReactor. Wizard automaticky prefixuje triedu symbolom RDS.
- Použitím ObjectARX Wizard pridaj funkciu openedForModify()
Preskúmaj súbory vytvorené ObjectWizard, "rObjectReactor.h" a "rObjectReactor.cpp".
- Pridaj kód do openedForModify() tak aby:
- Ak práve premiestňujeme (m_doRepositioning == true) tak sa vráť. (Použi DocVars.docData().<patričná premenná sem>).
- Ak nie je aktívny žiadny z monitorovaných príkazov (m_editCommand == false) tak sa vráť.
- Over že AcDbObject je odovzdaný do AcDbBlockReference entity, ak nie tak sa vráť.
- Nájdi meno AcDbBlockReference. Na to potrebuješ získať AcDbBlockReference definíciu bloku AcDbBlockTableRecord a vyhľadaj meno AcDbBlockTableRecord. (Použi AcDbBlockReference::blockTableRecord ()). Ak to nie je referencia bloku EMPLOYEE, jednoducho sa vráť.
- Ulož pozíciu objektu 'openedForModify()' do m_employeePositions (AcGePoint3dArray::append()).
- Ulož ID objektu 'openedForModify()' do m_changedObjects (AcDbObjectIdArray::append()).
- Vytvor reaktor inštancie AsdkEmployeeReactor.
- Vytvor globálny ukazovateľ na náš reaktor objektu. Umiestni reaktor do súboru "Project.cpp" nasledovne:
AsdkEmployeeReactor *pEmployeeReactor = NULL;- Vytvor inštanciu objektu pri zavádzaní aplikácie, umiestni to do 'InitApplication()' v súbore "Project.cpp".
pEmployeeReactor = new AsdkEmployeeReactor();- Keď sa aplikácie uvolňuje, vymaž reaktor objektu. Umiestni nasledovné do 'UnloadApplication()':
delete pEmployeeReactor;Pozn.: Tu vytvárame samostanú globálnu inštanciu AsdkEmployeeReactor (AcDbObjectReactor objekt), ako uvidíme neskôr túto inštanciu pripojíme k referencii bloku EMPLOYEE. Mohli by sme tiež vytvoriť novú inštanciu AsdkEmployeeReactor a pripojiť každú inštanciu na každú nájdenú referenciu bloku EMPLOYEE. Nám iba stačí vedieť že AcDbObjectReactor môže byť napojený na viac ako jeden objekt.
Implementácia používatelom definovanej funkcie 'attachEmployeeReactorToAllEmployee()'
Pozn.: Ako bolo skôr spomínané pridáme/odstránime prechodné reaktory k našim objektom použitím addReactor()/removeReactor(). Tu ideme pripojiť reaktory ku všetkým objektom referencie bloku EMPLOYEE. Nezabudni že viac ako jeden otvorený výkres môže obsahovať referencie bloku EMPLOYEE. Trieda AsdkDataManager obsluhuje CDocData triedy a na každý dokument je jedna CDocData trieda. V konštruktore triedy CDocData budeme volať používatelom definovanú funkciu 'attachEmployeeReactorToAllEmployee()'. Toto sa zavolá pre každý otvorený dokument v aktívnej relácii AutoCADu a tiež keď sa vytvorí nový výkres alebo sa otvorí existujúci výkres. Táto funkcia bude zodpovedná za pripájanie/odstraňovanie objektov AsdkEmployeeReactor pre každý výkres.
- Pripoj reaktor objektu ku všetkým referenciám "EMPLOYEE" ktoré sú už na výkrese. Napíš funkciu:
Acad::ErrorStatus
attachEmployeeReactorToAllEmployee(bool attach) , ktorá:- Získaj tabuľku bloku (AcDbDatabase::getBlockTable()).
- Získaj záznam modelového priestoru (AcDbBlockTable::getAt(), ACDB_MODEL_SPACE).
- Získaj iterátor záznamov tabuľky bloku (AcDbBlockTableRecordIterator, AcDbBlockTableRecord::newIterator()).
- Pohybuj sa po záznamoch modelového priestoru a hľadaj entity (AcDbBlockTableRecordIterator::getEntity()). Ak nájdená entita referencie bloku nie je EMPLOYEE objekt, jednoducho sa vráť.
- Ak nájdená entita je referencia bloku "EMPLOYEE", Pripoj globálny reaktor objektov (AcDbObject::addReactor()) alebo ak je parameter attach rovný false tak odstráň práve pripojený reaktor objektu (AcDbObject::removeReactor()).
- Nakoniec nezabudni vymazať iterátor a zatvoriť objekty.
- Zavolaj attachEmployeeReactorToAllEmployee() vo vnútri CDocData konštruktora.
Implementácia používatelom definovanej funkcie 'detachAllEmployeeReactors()'
- Keď uvolňuješ svoju aplikáciu, musíš odpojiť všetky reaktory objektu pripojené k entitám referencie bloku EMPLOYEE. Implementuj 'detachAllEmployeeReactors()' aby to urobila.
void detachAllEmployeeReactors()
Táto funkcia:
- Získa AcApDocumentIterator (acDocManager->newAcApDocumentIterator()). acDocManager je globálno makro ktoré sa používa na nájdenie AcApDocManager ktorý je zodpovedný za všetky dokumenty v relácii AutoCADu. Pozri sa na AcApDocManager v ObjectARX online nápovede pre detaily.
- Ulož ukazovatel na aktívny dokument, aby si mohol znova nastaviť pôvodný dokument po iterácii (acDocManager->curDocument()).
- Pohybuj sa po všetkych dokumentoch, urob každý dokument práve aktívnym a zavolaj attachEmployeeReactorToAllEmployee(false).
- Po iterácii, nastav aktívny dokument na ten, ktorý bol aktívny pred iteráciou.
- Zavolaj detachAllEmployeeReactors() pri uvolňovaní svojej aplikácie.
Pridaj a implementuj reaktor databázy pre aplikáciu
- Použi ObjectARX Wizard na vytvorenie triedy AsdkDbEmployeeReactor reaktoru databázy odvodenej z AcDbDatabaseReactor. Wizard automaticky prefixuje triedu symbolom RDS .
- Použitím ObjectARX Wizard pridaj funkciu objectAppended().
- Implementuj funkciu 'objectAppend()'.
- Skontroluj či otvorený objekt je AcDbBlockReference ( cast ). Keď nie, tak sa vráť.
- Získaj záznam tabuľky blokov tejto referencie. (AcDbBlockReference::blockTableRecord()).
- Získaj meno záznamu taabuľky bloku a skontroluj či je to referencia bloku EMPLOYEE. Ak nie, tak sa vráť. (AcDbSymbolTable::getName()).
- Pripoj AsdkEmployeeReactor reaktor objektu k otvorenej referencii bloku. (AcDbObject::addReactor()). Nezabudni že prezaráme databázu aby sme videli či každá referencia bloku EMPLOYEE je už pridaná a či tak pridávame reaktor objektu AsdkEmployeeReactor k referencii bloku.
- Vytvor novú inštanciu reaktora databázy pre každý nový výkres. To môžeš urobyť keď obdržíš správu kLoadDwgMsg vo funkcii acrxEntryPoint().
- Z nástrojového panelu ObjectARX Wizard, klikni na tlačítko 'ObjectARX entry point messages'.
![]()
Krok 7 Obr. 3 - Entry Point Messages v nástrojovom paneli ObjectARX Wizard- Z dialógového okna ObjectARX Entry Point Messages vyber správu 'kLoadDwgMsg'.
![]()
Krok 7 Obr. 4 - Dialógové okno ObjectARX Entry Point MessagesObjectARX Wizard vytvorí funkciu 'OnkLoadDwgMsg()' v súbore "Project.cpp".
- Vytvor nový AsdkDbEmployeeReactor objekt vo funkcii správ 'OnkLoadDwgMsg()'.
new AsdkDbEmployeeReactor (true, curDoc());- Preskúmaj súbory "rDatabaseReactor.h" a "rDatabaseReactor.cpp" vytvorené "kúzelníkom" ObjectARX Wizard.
Pozn.: Do konštruktora triedy AsdkDbEmployeeReactor pridáme náš reaktor databázy dokumentu použitím 'addReactor()' a taktiež inicializujeme premennú ukazovatela m_pAsdkDbEmployeeReactor na pripojenie k objektu AsdkDbEmployeeReactor reaktoru databázy. m_pAsdkDbEmployeeReactor je časťou triedy CDocData a pridal ho ObjectARX Wizard. Pri zatvorení výkresu, je zavolaný deštruktor ~CDocData, Tu skontrolujeme či m_pAsdkDbEmployeeReactor nie je NULL a vymažeme ukazovatel. Zavolá sa deštruktor pre triedu AsdkEmployeeReactor a odstráni reaktor databázy zavolaním 'removeReactor()'.
Testuj aplikáciu
Vytvor niekoľko referencií bloku EMPLOYEE ako si to urobil v rámci Kroku03. Pokús sa premiestniť (MOVE) tieto referencie bloku EMPLOYEE. Ulož výkres. Uvolni aplikáciu. Otvor uložený výkres a znovu zaveď aplikáciu. Potom príkaz MOVE nebude mať žiadny vplyv na referenciu bloku EMPLOYEE, pretože reaktory, ktoré sú pripojené, boli skutočne prechodné...
Práve si skompletizoval cvičenia učebnice ObjectARX 2000. Dúfam že si spokojný a želám ti veľa úspechu do budúcnosti ako programátorovi ObjectARX.