Táblázatos komponens testreszabása

táblázat logoA Java programozási nyelv egyik ismert GUI csomagja a swing. Ennek népszerű grafikus komponense az adatok táblázatos megjelenítését biztosító JTable komponens. A táblázatos megjelenítéshez több beállítás is szükséges. A JTable egy MVC komponens, így külön kezelendők a modell, nézet és a vezérlő funkcióihoz kötődő beállítások. A modell tárolja az adatokat például DefaultTableModel típusú objektumban, amiben szétválaszthatók a fejlécben és a többi cellákban található adatok. A nézethez tartozik a betűméret, a cellák színezése, az adatok igazítása, megjelenítése, a gördítősáv. A viselkedést, a felhasználói reakciót a vezérlő határozza meg, például rendezés, görgetés, fókusz, kijelölés, oszlopok sorrendjének cseréje.

Feladat

Készítsünk olyan Java swing-es kliensprogramot, amely tetszőleges adatforrásból (XML vagy JSON a hálózatról, JDBC adatbázis kapcsolatból, ORM leképzésből származó objektumokból) képes az átvett adatok grafikus felületen való táblázatos megjelenítésére JTable komponenssel! Építsünk arra, hogy az adatokon kívül metaadatok is rendelkezésünkre állnak! A megoldás legyen univerzális!

Képernyőképek

OracleHR képernyőkép

Modell

A táblázatos GUI komponenst kezdetben inicializálni kell, illetve a benne tárolt adatok is törölhetők, ha újrahasznosításra kerül a sor:

Ki kell nyerni a tároláshoz és a megjelenítéshez kötődő adatokat (1. lépés). A metaadatokból a for() ciklus előállítja az oszlopTomb-öt, és az oszlopTipusTomb-be kerülnek az Oracle adattípusból Java objektumtípusként megfeleltetett adatok. Előbbi a fejléc feliratainak szövegeit tartalmazza, és az utóbbi befolyásolja az egyes cellákban az igazítást, illetve hatással van adott oszlop rendezésére is:

Ki kell nyerni a tároláshoz és a megjelenítéshez kötődő adatokat (2. lépés). A while() ciklus végigjárja az eredménytábla sorait és Object típusú tömböt állít elő az összetartozó rekord mezőiből. Ezek először generikus listába kerülnek, majd onnan kétdimenziós Object típusú tömbbe:

Mi indokolja a tömbökből álló generikus lista ( adatLista) alkalmazását?

A while() ciklus végrehajtása előtt nem tudjuk lekérdezni, hogy mennyi rekordot kaptunk vissza, így nem tudjuk rögtön az adatTomb-be tenni az adatokat. A Java nyelvben a tömbök mérete fix, és a deklaráció során meg kell adni. Az eredménytábla metaadatai között megtalálható a mezők száma, ami felhasználható a kétdimenziós tömb oszlopszámaként. A generikus lista dinamikus, annyi elemből fog állni, ahány lépésben végrehajtódik a while() ciklus. Ezután a listától lekérdezhető az elemszáma ( adatLista.size()), és ezzel megvan a kétdimenziós tömb sorainak száma, ami eddig hiányzott. Persze használhatnánk Vector-t is a tömbökből álló generikus lista helyett (mert a DefaultTableModel-nek van olyan túlterhelt konstruktora, ami átvenné paraméterként), de ezt inkább nem tesszük, hiszen a Vector már régóta obsolete kollekció.

Előállítjuk a vizuális komponens mögötti adatmodellt. Öröklődéssel kiegészítjük két hasznos függvénnyel, így cellák rajzolása/renderelése és rendezése megkaphatja a szükséges adattípust ( getColumnClass()), valamint letiltható a cellák szerkeszthetősége ( isCellEditable()). Utóbbiak inkább a vezérléshez kötődnek, de modellen keresztül itt és így kell beállítani:

Végül a vizuális komponens mögötti adatmodellt kell átadni:

Nézet

Adott betűtípus, betűstílus és betűméret használható a táblázat fejlécében, celláiban, illetve a betűmérettől függhet a sorok magassága:

Hasznos ha JScrollPane típusú gördítősáv tartozik a táblázathoz, így dinamikusan megjeleníthető/elrejthető a függőleges/vízszintes gördítősáv:

Vezérlés

Az adatokhoz valahogyan hozzá kell jutni. Most JDBC kapcsolatot használunk és az Oracle HR sémából kérdezünk le adatokat, de a forráskód-részlet univerzális. A folyamat a következő:

  • Betöltjük a driver osztályt.
  • Autentikációval c kapcsolatot nyitunk az adatbázis-szerver felé.
  • Végrehajtjuk a lekérdező SQL parancsot.
  • Feldolgozzuk az eredményül kapott ResultSet típusú rs objektumot.
  • Végül lezárjuk a c hálózati kapcsolatot.

Ha engedélyezzük, akkor a megjelenő táblázat fejlécében az egyes oszlopok felirataira kattintva elérhetjük, hogy az adott oszlop típusának megfelelően növekvő vagy csökkenő sorrendbe átrendeződjenek az adatok:

A kivételkezelést nem részleteztük a fenti forráskódoknál, de természetesen kötelezően adott.

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

A feladat a Java SE szoftverfejlesztő tanfolyam 45-52. óra: Adatbázis-kezelés JDBC alapon, illetve Java adatbázis-kezelő tanfolyam 9-12. óra: Oracle HR séma elemzése, 33-36. óra: Grafikus kliensalkalmazás fejlesztése JDBC alapon, 2. rész alkalmaihoz kapcsolódik.

“Táblázatos komponens testreszabása” bejegyzéshez 15 hozzászólás

  1. Tipikus Exceles igény, hogy a táblázat páros és páratlan sorai más háttérszínnel jelenjenek meg. Kérhetek ehhez ötletet, hogy csináljam JTable-lel?

    Válasz
  2. Szeretnék egy olyan JTable cellát, aminek a háttérszíne részben megváltoztatható. Ha a cellát teljesen kitölti egy háttérszín, akkor azt meg tudom csinálni a ColorRenderer.java mintapélda alapján, ami így néz ki (Favorite Color oszlop):

    A mai dátumból kivonva a HIRE_DATE-et és osztva 365-tel megkapjuk kb. egy alkalmazott tapasztalatát. A cégnél eltöltött idő alapján. Ezt már összeraktam SQL-ben. Egy cellában szeretném megjeleníteni a háttérszín arányos kitöltésének beállításával az adatokat, valahogy így (Age oszlop):

    Arra gondoltam, hogy JPanel-be raknék egymás mellé két JLabelt. A balra lévőt színezném, a jobbra lévő fehér lenne. És a panel kerülne a cellába. Szeretnék támpontot kérni, hogy jó-e az irány, vagy inkább teljesen másképp induljak el. Köszönöm előre is.

    Válasz
    • Áron: tetszik, hogy ilyen konkrétan megfogalmaztad, hogy mit szeretnél. A linkekről beraktam a képeket a hozzászólásodba.
      Jól látod: ez a feladat a rajzolás felüldefiniálásával már nem oldható meg könnyen, ezért jó út a komponens alapú megközelítés. Az ötleted megvalósítható. Ugyanilyen konténer-elvvel építünk GUI-t általában. Azért nem javaslom, mert 3 komponenst használnál egyetlen adat megjelenítéséhez cellánként.
      Más utat javaslok, amiben 1 adathoz 1 komponens tartozik.
      A felső képeden látható, hogy a Vegetarian oszlopban JCheckBox osztályú objektumok jelennek meg. Abból kiindulva, hogy a JTable bármelyik cellájába “belerendereltethető” bármilyen swing-es komponens, így próbálkozz a JSlider folyamatindikátor beillesztésével. A cellákhoz javaslom egyéni ToolTip beállításaként a lekérdezett tapasztalati éveket (kerekítve vagy egésszé csonkolva – mint eltöltött teljes év).

      Válasz
        • Áron, tudod: mindenki annyit visz el a tanfolyamról, amennyit beletett. Örülök neki, hogy sikerült megoldanod.
          Nincs már több közös kontakt óránk, de egy következő csoporttal kb. október végén járunk majd ennél a témakörnél. Ha lenne kedved, szívesen látunk: gyere be és mutasd meg a többieknek, hogy meddig jutottál, hogyan gondoltad végig, hogyan fejlődtél. Ha szeretnéd, egyeztessük privátban.

          Válasz
  3. Balázs, szeretném módosítani az egyik órai JTable-ös példát. Ilyesmi kiválasztást szeretnék:

    Összeraktam, hogy 1:N kapcsolat van az adatok között, a JComboBox-ot bele tudom rakni a DefaultCellEditor és a DefaultTableCellRenderer összekötésével. A képen olyan a példa, hogy a táblázat minden sorában ugyanaz a választék a programozási nyelveknél.
    Azt szeretném, hogy a különböző sorokban különböző választék jelenjen meg a legördülő listákban. Három dologra tudnál válaszolni: megoldható ez, ha igen: hogyan induljak el, ill. ha megy ez az Oracle HR sémából, akkor milyen adatokkal csináljam?

    Válasz
    • Megoldható Lilla. Látom, nagyon igyekszel gyakorolni. Örülök, hogy már itt tartasz. Meg fog térülni.
      Az Oracle HR sémából például ezek az adatok (és a közöttük lévő kapcsolatok) alkalmasak arra, amit szeretnél:

      • alkalmazott levelet ír másik – kiválasztott – alkalmazottnak, aki a részlegében dolgozik,
      • alkalmazott levelet ír a vezetői közül az egyik kiválasztottnak (ez nehezebb feladat a hierarchia miatt).

      Az MVC-s projektben elérhető az EMPLOYEE_ID az adatbázis modell rétegből és/vagy a rekord sorszáma a JTable mögötti DefaultTableModel saját modell rétegből, ami(k)hez egyedileg hozzá tudod rendelni az adott sorban lévő JComboBox vizuális komponens mögötti DefaultComboBoxModel saját modellt adatforrásként.
      Mindkét esetben kezelni kell azt, ha nincs adat: például 1 fős részlegben nincs kollégája, vagy az organogramban nem áll felette senki.

      Válasz
      • Balázs: ezek a példák is jók ilyesmi táblázatos/kiválasztós nézethez?

        • X alkalmazott mobilizálható olyan alkalmazotta(ka)t keres, akik korábban részt vettek olyan projektben, amiben X még nem?
        • hol vannak olyan részlegek, ahol X alkalmazott nem dolgozik?
        Válasz
        • Igen Laci, mindkét példád alkalmas gyakorolni. Utóbbihoz beágyazott térkép is társítható, ha kétlépéses varázslót raksz össze: az 1. lépésben táblázatos a kiválasztás és a 2. lépésben navigálható térkép kerül az egyik órai feladat alapján a GUI-ba. A két lépés között váltani a JTabbedPane komponenssel lehet, amin a fülek megjelenítése tetszés szerint ki-/bekapcsolható.

          Válasz
  4. Balázs: Lillával dolgozunk a második példámon, amit jóváhagytál. A táblázatban nem jelenik meg az adatok kulcsa (ez az 1:N kapcsolatban az 1 oldal), mert ez nem kell a View-ba. Pedig a legördülő listához kell egy kulcs, mert ez az 1:N kapcsolatban a sok oldal). Hogyan oldjuk ezt meg? Még nem tartunk itt, de kelleni fog majd a válasz a befejezéshez.

    Válasz

Szólj hozzá!