Dátová časť simulačných komponentov
![]() |
Trenčianska Univerzita Alexandra Dubčeka v Trenčíne
Fakulta Mechatroniky |
![]() |
Dátová časť simulačných komponentov Diplomový projekt |
Autor: | Bc. Michal Janíček |
Pedagogický vedúci: |
Ing. Juraj Ďuďák |
Študijný odbor: | Mechatronika
|
Akademický rok |
2009/2010
|
1. | Platforma NetBeans |
2. | Vizuálna časť programu DynaSim |
3. | Dátová časť simulačných komponentov |
4. | Okná a toolbary programu DynaSim |
5. | Funkčná časť programu DynaSim
|
Obsah
Dátová časť simulačných komponentov
Widgety v sebe uchovávajú len grafickú časť komponentu. Druhý problém je, že na scéne môže byť len jeden widget z každého druhu, čiže by na scéne mohol byť len jeden Integer, len jeden Slider atď. Aby sme tento problém odstránili, je potrebné každý widget zviazať s inštanciou triedy, ktorá v sebe uchováva dáta. Dáta jednotlivých komponentov môžu predstavovať napríklad meno, kategóriu, cestu k SVG a XML súboru, vnútorné stavy a ďalšie potrebné údaje.
MyNode
Táto trieda predstavuje v DynaSimScene uzol samotný a SVG_Widget je len jeho grafickou reprezentáciou. Trieda samotná je na vrchole hierarchie, dedí len z triedy Object. Konštruktor je nasledovný:
public MyNode(String title, String category, String name, Point location)
Parameter title je názov komponentu, ten sa získava z XML dokumentu, category je meno kategórie do ktorej komponent patrí. XML dokument sa parsuje v konštruktore MyNode, ale aby sme získali jeho meno, potrebujeme XML parsovať ešte predtým. To sa vykonáva v triede BrowseFolders pri tvorbe palety. Meno kategórie je vlastne meno adresára v ktorom je uložený SVG a XML súbor daného komponentu. Name je názov SVG/XML súboru bez prípony a location je miesto, na ktoré sa widget prilepí na scénu. V konštruktore sa inicializujú niektoré premenné z parametrov a zavolá sa metóda readXML(), pomocou ktorej sa rozparsuje XML súbor, ktorého cesta sa poskladá z mena kategórie a mena súboru, ktoré sme získali z parametrov. Miesto kde sa nachádza knižnica samotná sa získa z metódy getLibraryFolder() inštancie triedy FolderSearcher. FolderSearcher je trieda, ktorá slúži na hľadanie cesty ku knižnici s XML súbormi pre DynaSim. Táto knižnica má názov “library“ a nachádza sa v projekte DynaSimu. FolderSearcher teda začne hľadať v projekte a postupuje hlbšie v adresároch kým nenájde adresár s názvom “library“. Absolútnu cestu k tomuto adresáru si uloží medzi členské premenné a dostať sa k tejto ceste je možné cez metódu getLibraryFolder(). Tvar v akom cestu k adresáru vráti je závislý od operačného systému.
Štruktúra XML súboru simulačného komponentu
Zápis XML súboru komponentu môže vypadať nasledovne:
Dáta získané z parsovania takéhoto XML súboru v triede MyNode nám po označení komponentu na scéne vygenerujú PropertySheet, ako môžeme vidieť na obr.10. Ako vidno z časti kódu, root element má názov component a má len jeden atribút s názvom name. Podľa tohto atribútu sa vygeneruje meno pre daný komponent s priradeným poradovým číslom. XML súbor nie je kontrolovaný podľa DTD súboru. Priame detské elementy root elementu sú input, output, properties, desctiptionm, jython. XML môže mať ľubovoľný počet elementov s menom input a output. Input predstavuje vstupný pin, output výstupný. Ich atribúty x a y určujú polohu pinu v rámci komponentu. Je vhodné zvoliť ich tak, aby neboli mimo hraníc komponentu, ktoré sú určené v root elemente SVG súboru. Element name je meno terminálu, môže byť ľubovoľné a type určuje, aký dátový typ daný terminál v sebe drží.
Element properties by mal byť v XML súbore len jeden, ten však môže obsahovať ľubovoľný počet elementov s menom property. Property predstavuje jednu vnútornú premennú, tá je definovaná piatimi elementmi ako vidieť v ukážkovom kóde. Detský element type určuje akého dátového typu je daná premenná. V súčasnosti sú implementované tieto typy: BOOL – ktorý predstavuje boolean hodnotu, INT – hodnotu typu int, FLOAT – float, STRING – String.
Element Description má 3 detské elementy, slúži na opis komponentu. Na obr.10 môžeme vidieť, ako sa textové hodnoty týchto elementov prejavia na Property Sheete.
MyEdge a MyPin
MyEdge a MyPin predstavujú dátovú vrstu pre spojovaciu čiaru a pin. Každému pinu sa pridelí po jeho vytvorení cez generátor unikátne číslo a to sa zapíše do členskej premennej MyPin s názvom id ako String. Každý MyPin má getter a setter pre premennú typu Point. Hodnota tohto bodu sa získava z XML súboru a používa sa na prilepenie pinu na zvolené miesto v rámci komponentu. MyPin ešte obsahuje premennú typu boolean s názvom isInput. Tá určuje či je pin vstup alebo výstup. Táto informácia as taktiež získa z XML súboru a ak je element typu input, isInput má hodnotu true, ak je element typu output, isInput má hodnotu false.
MyEdge je tiež tvorené len gettermi a settermi. Má 2 premenné typu String s menom source a target. Tie predstavujú id pinov, ktoré sú spojené touto čiarou.
Tvorba Properties okna pomocou MyPropertyNode
Na editačnú plochu simulátora si užívateľ pridáva simulačné komponenty z palety. Po kliknutí myšou na niektorý z takto pridaných komponentov vyžadujeme, aby sa vygenerovalo okno s hodnotami komponentu, ktoré môže užívateľ upravovať. MyPropertyNode má na starosti vytvorenie Properties okna z údajov obsiahnutých inštanciou MyNode. Príklad takéhoto okna je možno vidieť na nasledovnom obrázku:
Aby sa takéto okno po označení nejakého komponentu vygenerovalo, musí byť splnených niekoľko nutných podmienok. V prvom rade sa musí vyriešiť medzimodulová komunikácia. Kým sa modul DynaSim stará o editačnú plochu, ktorá je v okne editor, nachádzajúca sa v centrálnej časti programového interface, okno Properties sa nachádza v okne properties, ktoré sa štandardne nachádza v pravej dolnej časti programu a je riadené modulom Nodes API. Ten treba pridať ako závislosť na modul DynaSim. Tým sa však ešte komunikácia medzi modulmi nevyriešila, lebo okno properties stále nebude vedieť, či je vôbec niečo v okne editora označené. Na to existuje trieda Lookup. Za normálnych okolností môže mať jeden TopComponent len jeden Lookup, avšak DynaSimTopComponent potrebuje dva, jeden pre Property okno a druhý nesôkôr pre paletu. To sa dá obísť cez vytvorenie InstanceContent:
private InstanceContent content = new InstanceContent();
V konštruktore DynaSimTopComponentu potom vytvoríme abstraktný lookup a pridáme ho Topcomponentu nasledovne:
associateLookup(new AbstractLookup(content));
InstanceContent content sa potom prenáša medzi triedami ako premenná v ich konštruktore, z DynaSimTopComponent-u do DynaSimScene, z tej ďalej do Component_Widget – po pridaní simulačného komponentu na plochu editora. Component_Widget má zdedenú metódu z triedy Widget s názvom notifyStateChanged, ktorá sleduje zmenu stavu widgetu. Nasledovná časť kódu je z tejto metódy a rieši, čo sa stane po kliknutí na komponent na editačnej ploche.
if(newState.isSelected()){ propNode = new MyPropertyNode(this.getNode()); content.set(Collections.singleton(propNode), null); content.add(controller); } else { if(propNode!=null) try { propNode.destroy(); } catch (IOException ex) { Exceptions.printStackTrace(ex); }
Ak je komponent označený vytvorí sa nová inštancia MyPropertyNode, kde sa za parameter dosadí MyNode inštancia zviazaná s týmto komponentom. V ďalšom riadku sa novovytvorená inštancia uloží do content. A tým sme vlastne dosiahli, že sa nám po kliknutí na simulačný komponent vytvorí propertySheet. Problém je, že sa nám potom stratí paleta, preto treba znova pridať cez content.add kontrolér palety. Slučka else rieši, čo sa stane, keď sa objekt odznačí, napr. Kliknutím na editačnú plochu. Metóda propNode.destroy() zruší túto MyPropertyNode a tým sa Properties okno vynuluje. Aby toto všetko mohlo fungovať aj trieda MyPropertyNode musí spĺňať jednu podmienku a to, že musí byť rozšírením AbstractNode triedy. Jej deklarácia je nasledovná:
public class MyPropertyNode extends AbstractNode implements PropertyChangeListener
Konštruktor:
public MyPropertyNode(MyNode node) { super(Children.LEAF); this.node = node; }
AbstractNode má v konštruktore parameter pre inštanciu triedy Children, pretože sa obvykle používa pri stromových štruktúrach uzlov. V našom prípade však máme len samostatné uzly typu MyNode a nemajú ďalšie detské uzly, preto sa použije LEAF ako koncový uzol. MyPropertyNode má metódu createSheet(), ktorú zdedila z AbstractNode. Táto metóda slúži na vytvorenie Property okna typu Sheet a jeho naplnenie položkami a ich príslušnými hodnotami. Na začiatku sa vytvorí nová inštancia triedy Sheet. Vytvorením inštancie Sheet.Set sa vytvorí nový blok v Properties okne a cez set príkazy mu je možné prideliť meno a popis. Jednotlivé hodnoty položiek, ktoré sa majú v takomto bloku zobrazovať sa nachádzajú v inštancii triedy MyNode. Ako tieto hodnoty zobraziť v Properties okne sa dá jednoducho ukázať na nasledovnom príklade:
Property categoryProp = new PropertySupport.Reflection (node, String.class, "getCategory", null);
Konštruktor triedy Reflection je nasledovný:
Reflection (Object o, Class type, String method1, String method2);
Object o predstavuje triedu z ktorej chceme danú hodnotu získať resp. nastaviť cez Properties okno. Class type je typ premennej s ktorou chceme pracovať, to môže byť int.class, String.class a pod. String method1 predstavuje názov getteru pre túto premennú a method2 názov setteru v s Stringu. Ak má method2 hodnotu null nie je možné meniť jeho hodnotu pomocou Properties okna. Z toho vyplýva, že v predošlom príklade chceme z inštancie node typu MyNode získať premennú dátového typu String. Názov getteru je getCathegory() a nie je možné meniť túto hodnotu cez setter v Properties okne.
Gettery a settery sa logicky musia nachádzať v triede MyNode. Každá premenná ktorú chceme zobraziť v Properties okne musí mať minimálne svoj getter a v prípade, že ju chceme v okne aj editovať musí mať aj setter. Štandardne má každý komponent 5 základných hodnôt, ktoré ho opisujú a to je Name, Category, Type, Function, Description (obr.10). Name je jediná meniteľná položka, ostatné sú nemenné Category je meno adresára v ktorom je uložený XML súbor a ostatné položky sa získajú parsovaním tohto XML dokumentu.
Mimo týchto základných položiek môže mať komponent aj ďalšie. Tie opisujú hodnoty jeho vnútorných stavov. Každý komponent by mal mať ľubovoľné množstvo vnútorných hodnôt, ľubovoľného dátového typu. Tu však nastáva vážny problém! Každá z týchto hodnôt musí mať svoj vlastný getter a setter, a keďže Java nedokáže za chodu programu do triedy dopisovať metódy musia sa do triedy napísať pred kompilácoiu. Inými slovami, ak očakávame, že žiadny komponent nebude mať viac ako 6 vnútorných hodnôt musíme vytvoriť 6 getterov a 6 setterov pre int, 6 getterov a 6 setterov pre float atď. Takže treba vytvoriť v triede MyNode gettery a settery pre všetky dátové typy s ktorými chceme v programe DynaSim pracovať. Počet týchto getterov a setterov obmedzuje možný počet hodnôt, ktoré možno zobraziť a upraviť v Properties okne. Ak budeme mať 3 gettery a settery pre každý dátový typ, Properties okno nebude schopné zobraziť viac ako 3 prvé položky. Ak teda uvažujeme, že chceme mať komponenty so 100 vnútornými hodnotami, potrebujeme vytvoriť 100 getterov a 100 setterov pre každý dátový typ!!! Z toho dôvodu je súčasná verzia programu obmedzená na 6 vnútorných hodnôt pre dátové typy int, float, boolean a String.