Fát építünk

Fát építünkAz adatok strukturális és könnyen értelmezhető formában való megjelenítése egy szoftver felhasználói felületén átgondolt tervezést igényel. Az adatokhoz hozzá kell jutni, ki kell választani a megfelelő grafikus komponenst, a mögötte lévő adatmodellt, össze kell ezeket kötni. Gyakran előforduló feladat, hogy táblázatosan is ábrázolható adatokból – felhasználva az adatok közötti összefüggéseket és kapcsolatokat – csoportosítva jelenítsünk meg hierarchikusan, fa struktúrában, kinyitható-becsukható formában, ahogyan ezt a felhasználók jól ismerik a fájl- és menürendszereket használva.

Fát építünk kétféleképpen

Adatbázisból, az Oracle HR sémából lekérdezünk két összetartozó nevet: részleg és alkalmazott. A lekérdezés során figyelünk a megfelelő sorrendre, ami a későbbi feldolgozást megkönnyíti. Adatainkat részlegnév szerint növekvő, azon belül alkalmazott neve szerint is növekvő – ábécé szerinti – sorrendbe rendezzük. A vezérlő rétegben két függvényt írunk, amely a modell rétegtől jut hozzá az adatokat tartalmazó generikus listához – átvett paraméterként –, és a visszaadott érték a nézet réteghez kerül.

A csoportváltás algoritmust használjuk, amely 5 blokkból épül fel. A külső ciklus előtti 1. blokk és utáni 5. blokk egyszer hajtódik végre, az előkészítő és lezáró tevékenységek tartoznak ide. A külső ciklus elején és végén található 2. és 4. blokk a belső cikluson kívül fut le, csoportonként, kategóriánként, részlegenként egyszer (most összesen 11-szer mindkettő). A 3. blokk a belső cikluson belül található, és alkalmazottanként egyszer hajtódik végre (most összesen 106-szor).

Háromszintű fát építünk: a gyökérbe (0. szint) fix, beégetett szövegként kerül a cég neve és a teljes létszám. Az 1. szinten jelennek meg a részlegek nevei és a hozzájuk tartozó létszámok. A 2. szint az alkalmazottak neveiből áll.

1. megoldás

A megoldás faKeszit1() függvénye szöveges adatot eredményez. Ez jól használható teszteléshez: megvan-e az összes adat, megfelelő-e a részlegek sorrendje azon belül az alkalmazottak sorrendje, működik-e a csoportosítás, rendben van-e a megszámolás?

A faKeszit1() függvény egy sok lépésben összefűzött (konkatenált) szöveget ad vissza. Az 1. blokkban előkészítjük a fa gyökerét, ami StringBuilder típusú, hiszen sokszor manipuláljuk és inicializáljuk a lista indexelésére használt i ciklusváltozót. A 2. blokkban megjegyezzük az aktuális részleget és előkészítjük az ehhez tartozó alkalmazottak nevét tároló generikus listát ( faReszlegAlkalmazott). Az aktReszleg-hez tartozó alkalmazottak neveit összegyűjtjük a 3. blokkban. Egy részleg feldolgozását a 4. blokkban fejezzük be a fa aktuális 1. és 2. szinten lévő elemeinek szövegbe való beszúrásával. A belső ciklushoz kötődően megszámolást nem kell alkalmaznunk, hiszen az adott részlegben dolgozó alkalmazottak száma a generikus listától elkérhető ( size()). Építünk arra, hogy a külső ciklusból nézve az egymás után végrehajtódó 2. és 4. blokkban az aktReszleg nem változik meg. A 2. blokkban még nem tudjuk a fa aktuális 1. szintjét hozzáfűzni a szöveghez, hiszen a létszám csak a belső ciklusban felépülő kollekciótól kérhető el utólag. Szükséges némi késleltetés, hiszen a szöveg összefűzése és lényegesen egyszerűbb (mint utólag manipulálni megfelelő helyeken). Az 5. blokkban a csoportváltás algoritmushoz kötődő tevékenységünk nincs.

Az 1. megoldás eredménye

2. megoldás

A faKeszit2() függvénynél alkalmazkodunk ahhoz, hogy a JTree vizuális komponenshez DefaultTreeModel observable típusú modell szükséges, így ezzel térünk vissza ( faModell). A fa csomópontjai DefaultMutableTreeNode osztályú objektumok lesznek, amelyeknek a userObject tulajdonsága szükség esetén manipulálható. Az 1 blokkban beszúrjuk a fa gyökerét ( faGyoker), amihez a későbbiekben csatlakozik a fa többi eleme. A 2. blokkban megjegyezzük az aktuális részleget és előkészítjük – megjelenítendő szöveg nélkül – a faReszleg csomópontot. A 3. blokkban fabeli csomópontként a fa 1. szintjén megjelenő részleghez névtelenül hozzáadjuk a fa 2. szintjére kerülő – aktuális részleghez tartozó – alkalmazottak nevét. A 4. blokkban utólag módosítjuk a faReszleg csomópont megjelenítendő szövegét. Az aktuális részleg létszámát itt sem kell külön megszámolni, mert a faReszleg-től elkérhető ( getChildCount()). Az 5. blokkban itt sincs különösebb teendőnk.

A 2. megoldás eredménye

Fát építünk, képernyőkép

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

Attól függően, hogyan jutunk hozzá a megjelenítéshez szükséges adatokhoz, több tanfolyamunkhoz is kapcsolódik a feladat és a modell rétegben mindig másképpen tervezünk és implementálunk:

  • A Java SE szoftverfejlesztő tanfolyam 45-48. óra: Adatbázis-kezelés JDBC alapon, 1. rész alkalmán hagyományos SQL lekérdező utasítást készítünk JDBC környezetben.
  • A Java EE szoftverfejlesztő tanfolyam 25-32. óra: Adatbázis-kezelés JPA alapon alkalommal a perzisztencia szolgáltatásait vetjük be.
  • A Java adatbázis-kezelő tanfolyam 13-16. óra: Konzolos kliensalkalmazás fejlesztése JDBC alapon, 1. rész, 33-36. óra: Grafikus kliensalkalmazás fejlesztése JDBC alapon, 2. rész alkalmain hierarchikus lekérdezéseket használunk.

Ajánljuk a Java SE szoftverfejlesztő tanfolyam kategóriából

“Fát építünk” bejegyzéshez 11 hozzászólás

  1. Íme a gyakorló feladat a mai órához kapcsolódva.
    Van egy olyan alkalmazott az adatbázisban, akinek nincs részlege. Ő kimaradt mindkét fenti megoldás esetén a fából. Hogyan lehetne megoldani, hogy az ő neve (Kimberely Grant) is megjelenjen például a részlegek szintjén vagy egy fiktív (üres, null) csomópont alatt?

    Válasz
  2. Ezt szeretném megoldani, bedobom a következő órára. Adott egy tárhelyen egy blogmotor néhány userrel. Mindenki posztolhat, amihez feltölthet képeket. A képek sajnos /ev/ho mappaszerkezetbe kerülnek (nem posztonként, nem userenként), amin nem akarok változtatni. A userekhez külön kvóta nincs. Fájlonként van max. méret, amit fel tudnak tölteni, de user által össz. feltölthető MB-ot nem tudok beállítani. Vagy csak nem találtam? Arra gondoltam, hogy a faépítő programból ki lehetne indulni és összeszámolni a userhez tartozó posztokhoz tartozó képek méreteit és ez egyrészt megjelenhetne az admin felületen, másrészt kaphatnának emailt, ha elérték a limit 80%-át, 90%-át. Ahogyan a mobil szolgáltatók is figyelmeztetnek időnként az elhasznált adatkeret x%-ánál. Tudom, kicsit túlgondoltam, de érdekelne. Kíváncsian várom, ki mit tesz majd hozzá az órán.

    Válasz
    • Endre: a néhány user könnyen összepárosítható a nem túl mély ev/ho mappaszerkezettel. A fába tetszőlegesen tehetsz a fenti mintában látható megszámolt adat helyett összesített adatot (akár posztonként is). Az SE tanfolyamon a fa megjelenítéséig és a figyelmeztetés kiválogatásáig/eldöntéséig eljutunk. Az EE tanfolyamon megtudhatod majd, hogyan lehet mindezt időzíteni, hogyan küldhető ki a figyelmeztető e-mail… Én is várom, mit tesznek hozzá a többiek a keddi órára készülve: dobd be a témát az ILIAS fórumba.

      Olyan kvótát is láttam, ami a feltöltött fájlok egyéni méretén túl a posztok méretét is limitálta. Például 5 MB/poszt. Ezt lehet posztonként szigorúan kezelni (így könnyebb), vagy user-enként összesítve (így nehezebb).
      Az is részfeladat még, hogy a helyi mappaszerkezet bejárásához hasonlóan hogyan kell egy távoli szerveren lévő mappaszerkezetet bejárni.
      Ezekre Balázs mutat majd példákat a keddi órán.

      Válasz
  3. A saját példámból indulok ki. A munkahelyemen a heti 40 órás munkaidőmet 3 csoportvezetőtől kapott feladataim töltik ki. Kb. 8-16-16 arányban. Jó ötlet lenne engem úgy beletenni a fenti fába, hogy az adott csoportvezető alá a nevem mellé kerülne az óra vagy %, azaz hogy időarányosan mennyire tartozom alá?

    Válasz
    • Megvalósítható a részmunkaidő-keret alapján az ötleted Linda. Órával és százalékkal is megy. Még izgalmasabb lenne valahol tárolni a 40 órát max-ként és úgy felosztani bármennyi részre, hogy az összeg mindig 40 legyen. Ezt nem egyetlen egyszer kihívás rögzíteni, hanem a folyamat/életciklus, hiszen előfordulhat módosítási, szerkesztési igény.

      Válasz
  4. Ha nagyon sok szinten sok adat kerül a fába, akkor azt vettem észre, hogy lassú a megjelenítés. Nem mértem, csak látszik, érezhető. Hát ezt most nem túl kocka módon írtam, de lehet valamit tenni? Lehet, hogy elrontottam a házi feladatot, azért lett ilyen sok adat. Tanulunk erről valamikor Sándor?

    Válasz
    • Örülök, hogy felmerült a probléma, mert tanulságos. Látszik, hogy figyelmesen gyakorolsz Marcell. (Aki még nem tart itt: van egy olyan gyakorló feladatunk, amiben közel 2000 db adatot kell 4 szintű hierarchiában egy fában értelmesen, kereshetően, navigálhatóan megjeleníteni.)

      A Java SE szoftverfejlesztő tanfolyamon (amivel most foglalkozol) nem jutunk el a megoldásig, de teszteljük és észrevesszük a swing GUI komponensek határait és egyensúlyozunk az MVC-ben.

      A Java EE szoftverfejlesztő tanfolyamon a szálkezelésnél van ilyen problémát megoldó mintapéldánk. A kulcsszó: SwingWorker. Az elv az, hogy nem töltjük be a modellbeli összes adatot egyszerre a JTree komponens adatmodelljébe (hogy megjelenjen), hanem késleltetjük (lazy loading) a folyamatot. Egy-egy elemet (a fában alatta lévőkkel együtt) csak akkor bontunk ki (töltünk be, jelenítünk meg), amikor rákattint a felhasználó.

      Válasz

Szólj hozzá!