Konfigurálható dialógusok

Fórumok

Viszonylag nagy mennyiségben lenne szükségem dialógus ablakok legyártására. Így felmerült bennem, hogyha már kínlódok vele, akkor valamilyen univerzális lehetőséget kellene beépítenem a rendszerbe.
Ezen azt értem, hogy a dialógusokat nem fixen előre gyártanám le, hanem a program futásakor adnánk meg, hogy mi legyen bennük. Pl. vehetnénk egy adatbázisból, hogy milyen elemekre van szükség, azokat milyen speciális feltételekkel kell előállítani, stb...

Vegyünk egy egyszerű példát!
Kiolvassuk az adatbázisból, hogy a következő dialógus, amit meg szeretnénk jeleníteni két sorból fog állni.
Így rögtön létrehozunk egy dialógust, aminek mondjuk van két üres sora (pl. GridLayout), és alul egy „OK” és egy „ESCAPE” gomb.
Majd sorban kiolvassuk, hogy konkrétan milyen adatbeviteli elemekre van szükség a két sorban, és azokat is legyártjuk és hozzá adjuk a dialógushoz. Pl. az egyik sorban egy TextField a másikban egy ChekBox. Stb..

Szóval a kérdésem az, hogy ismertek-e Java nyelven (elsősorba ingyenes) konfigurálható (parametrizálható) dialógusok előállítására képes szoftvert?
Ha igen, osszátok meg velem, és persze a HUP olvasótáborával, ezt az információt!

Hozzászólások

Ha általános dolgot akarsz, arra ott a JOptionPane. Azt elég jól kitalálták.

Ha valami "speciálisabb általánosra" van szükséged akkor meg definiálni kell, h miben speciális és mennyire általános :-)
Mondom a saját példámat, h valami fogodzót is adjak. Olyan dialógusokat gyártok szakmányban, melyek különféle űrlapokat tartalmaznak. A dialógus csak egy keret, amely bizonyos általános tulajdonságokat, viselkedést (kinézet, panel modelljének validálása, dialógus megjelenítése, lezárása, konkrét panel típus példányosítása stb.) ad, az igazi tartalom az űrlapok paneljében valósul meg, melyek egy ősből származnak:


public abstract class AbstractFormPanel<T> extends JPanel {
    protected abstract void setModel(T t);
    protected abstract void checkModel() throws InvalidInputException;
    public abstract T getModel();
}

Mint látható, a generikus típus paraméter a panel modellje (vö. JTable és az ő TableModel-jével)
A leszármazottal definiáljuk a konkrét modell típust.
A leszármazott dialógus is egy ős dialógusból származik,


abstract public class AbstractFormDialog<T> {
    ...
    abstract protected AbstractFormPanel<T> createPanel();
}

de nem sok dolga van, a leszármazott panellel összhangban definiálom, pl:


class AddressDialog extends AbstractFormDialog<Address> {

    public AddressDialog(JComponent c, String title) {
        super(c, title);
    }


    @Override
    protected AbstractFormPanel<Address> createPanel() {
        return new AddressPanel();
    }

}

Ahol az AddressPanel:


class AddressPanel extends AbstractFormPanel<Address> {..}

valósítja meg az UI-t, amivel a felhasználó dolgozik.

Bár a JOptionPane is elég általános, h ilyesmit meg lehessen oldani vele, a testreszabás és a kód egységessége miatt így kényelmesebbnek találtam. Nyilván ezt is lehetne másképpen, talán elegánsabban is, de példának jó lesz.

- készítesz egy MachineModel-t, melynek két mezője van
- készítesz egy MachinePanel-t, ami ilyen modellt vár, a modell mezőit tölti be a panel megfelelő Swing komponenseibe, ill. olvassa ezekből ki az értékeket és teszi bele a modellbe a dialógus bezárásakor
- készítesz egy MachineDlg-ot, ami a MachinePanellel dolgozik

Elmondva soknak tűnhet, különösen a másik tanács (MetaWidget: megadsz két típust oszt jónapot) fényében. De: meg kell nézni, hogy egy ilyen framework mit vár el, milyen megkötéseket tartalmaz, mennyi idő/energia befektetés a használata, mennyire köt magához stb. Mert az egyszerűségnek sokszor van elsőre nem látszó ára.

Ha a paneleket is kézzel akarod megcsinálni, és nem generáltatni valamiféle deklaratív leírás->kész widget keretrendszerrel, akkor nyilván kell valami leíró, vagy konvenció az adatmodell class-widget class összeköttetés leírására. Ezt tárolhatod db-ben, property fileban, XMlben, ahogy jól esik. Ide a DB szerintem eléggé overkill, felesleges. Inkább egy beépített konvenció a legegyszerűbb: adatmodell osztályok mondjuk com.example.XYModell nevet napnak, a szerkesztőik meg com.example.XYModellEditor nevet, így már Class.forName-mel tudod inicializálni őket, és hasonló. Bővebb problémaleírással jobb tervet is lehetne adni, konkrétabbat, de így csak általánosságban tudunk beszélgetni.

Nem tudom, mennyire lesz még világosabb a célom, de megpróbálom kicsit bővebben elmagyarázni.
Szóval űrlapokat kell kitöltetnem egyelőre nagyságrendileg 25-30 félét. De idővel ezek száma növekedni fog (akár több száz is lehet) és esetleg változhatnak is. Az űrlapok verziókövetése megoldott. Ezzel nincs gond. A kitöltött űrlapok tartalmát adatbázisban kell tárolnom. Ez is biztos. Mivel hosszú távon alkalmassá szeretném tenni a programomat a feladat ellátására ezért gondoltam arra, hogy az űrlapok előállítása úgy történne, valamilyen adathalmazból venném az egyes adatok beviteléhez szükséges leírást. A leírást jól definiált módon könnyen elő lehetne állítani. A programomban csak beolvasnám a leírást, és annak megfelelően előállítanám a dialógus ablakot. Szóval, ha változna valami az űrlapon nem kellene a forráskódban turkálni és módosítani, hanem a leírást módosítanám, és kész.
Nem tudom, így már érthetőbb?

Végig csináltam az általad ajánlott mintapéldát. (Lényegében ez van a videón is.) Működik. Csakhogy az alábbi problémákat látom benne:

1, Létre kell hozni az adatokat konfiguráló xml fájlt. Ez nem is lenne baj, csakhogy ezt már futásidőben meg kell tenni fixen. Azért mondom, hogy fixen, mert bele kell tenni az „src” könyvtárba, hogy bele forduljon majd a jar-ba. Így aztán nem lehet módosítani. Én úgy szeretném, ha ezt a konfiguráló fájt én hozhatnám létre futásidőben. Tehát úgy működne a dolog, hogy a konfigurációt előbányászom valahonnan, és azzal az aktuális konfigurációval kellene létrehozni a dialógusomat. Szóval ez a jelenlegi módszerrel nem megy, ahogy én látom első megközelítésben.

2, Bármennyire is rugalmas a rendszer, mégiscsak kell írni valami primitív kódot a forrás állományba. Ennek nagyon sok hátránya van. Pl. ha egy újabb űrlapot kell beiktatnom a rendszerbe, akkor hozzá kell nyúlnom a forráskódhoz. Tehát egy újabb verzióját kell majd kiadnom a programnak. Nyílván, ezáltal nem is akárki tudja majd megcsinálni az újabb űrlapokat, csak a programozás rejtelmeibe beavatott személyek. Szóval ez a része sem tetszik igazán. Sőt ezek miatt nem is tudom használni.

3, Egy apróság: Az adatbeviteli elemek előtti címkéket a forráskódban szereplő változó nevekből határozza meg. Ez is amiatt nem jó, hogy azt valamilyen külső adatbázisból kellene venni.

Tehát összefoglalva: A legalapvetőbb hiányossága, számomra, a rendszernek, hogy már fordítási időben meg kell alkotni a dialógusokat, nem lehet futási időben megmondani, mi legyen bennük.

Elvileg a metawidget azt mondja magarol, hogy o runtime kiszedi az adatokat a babokbol, en nem ertek hozza.

Ha esetleg nem ragaszkodnal annyira a javahoz, a vilag osszes tobbi programozasi nyelven es/vagy kornyezeteben ezt azert mar elegge megoldottak. (Nyilvan a java pride ott kifullad, hogy erre is van lib mint mindenre)

De alapvetoen annyira aze' nem bonyesz irni egy leirofajlformatumot, nezz utana a composite mintanak a design patterns konyvben, aztan egyszeruen valami hashmapben eachelve osszehozod. Lehet a design patterns wikin meg pluszba van is erre megoldas, en lattam c++ -os rendszereket ilyet csinalni 1998-ban.

1. Szerintem megoldható, hogy ne a jar-ban keresse az xml-t, hanem valami útvonalon és onnan olvassa fel. De akkor megint ott van, hogy szerintem nem lehet minden kontroll nélkül átírni bármit és várni, hogy az alkalmazás majd automatikusan alkalmazkodik, hogy mivel mit csináljon.

2. Ha valami újat akarsz, akkor szerintem törvényszerű, hogy valamihez hozzá kell nyúlni.
De ha csinálsz egy új űrlapot, akkor honnan fogja tudni az alkalmazás, hogy például küldéskor mit csináljon a megadott adatokkal?

3. @UiLabel és ehhez használható egy ResourceBundle, elvileg. De megoldható adatbázisból is, ha jól látom.

honnan fogja tudni az alkalmazás, hogy például küldéskor mit csináljon a megadott adatokkal?

Úgy gondoltam, hogy minden adatot String-ben adna vissza, bármilyen típus is lenne egyébként az adott sorban. Az adatbázisba való felvitelnél úgyis egy szöveges ("INSERT ...") karakterláncba kell beraknom az adatokat.
Egyébként pedig az űrlap adatainak mindig létrehozunk adattáblákat, olyan oszlopokkal és olyan sorrendben, ahogy a dialógus ablakban van. Így egyértelmű, hogy mit hova kell letárolni.

hogy minden adatot String-ben adna vissza
Hááát. Azért az jó nagy böszmeség lenne. Amikor olyan szépnek tűnik ez a metawidget dolog, te meg mindent stringelni akarsz?! A szöveges INSERT-elés meg ORM rendszerek mellett eléggé old-school megoldás.

Az rendben van, hogy létrehoztok adattáblákat és oda kellene tölteni, de meg is kell mondani a szerencsétlennek, hogy "töltse" oda. Persze fogsz egy entitást és perzisztálod egyszerűen (és akkor nem kell hozzányúlnod esetleg az akciókhoz, ha entitást módosítasz), ami szép is és jó is, de ha felveszel egy új mezőt, akkor az entitásnak is tükröznie kell ezt az új mezőt, nem megy az csak úgy magától, hogy te felvettél egy macilaci varchar2(100) mezőt és hopp legyen ott egy mező az UI részen is, mert te csináltál DB szinten egy alter-t. De az sem megy magától, hogy csináltál egy új táblát és magától ismerje fel, hogy az ott akkor form lesz. Persze mindent lehet szépen generáltatni.

A program ne írja meg saját magát esetleg? :)

A program ne írja meg saját magát esetleg? :)

Azt ne, de amit szeretnék az realizálható, szerintem. Be kell töltenie, hogy milyen adatbeviteli sorokból áll. Ezeket meg kell tudnia jeleníteni. Az "OK" gombra való kattintásnál pedig minden sor adja vissza a bevitt értéket. A többit majd lekezelem. Tehát azt, hogy melyik adattáblába, milyen sorrendbe kell bírni a bevitt adatokat. Stb...
A topic-ot ezzel a céllal indítottam. Azaz találni egy olyan dialógus felépítő rendszert, aminek nincs szüksége arra, hogy egy újabb űrlap megalkotásához valamit is módosítani kelljen a forráskódban. Ez a cél. És meg is fogom csinálni, ha nincs alapból egy ilyen rendszer. (Bár biztosan nem olyan jó színvonalon, ahogy ezek a profi programok meg vannak írva.)

Azaz találni egy olyan dialógus felépítő rendszert, aminek nincs szüksége arra, hogy egy újabb űrlap megalkotásához valamit is módosítani kelljen a forráskódban
És ezt hogy akarod kivitelezni?
Azt mondod a DB-ben, hogy create table és ezzel a lendülettel létre is jön a megfelelő UI form üzleti logikástól vagy hogy?

Nem teljesen így, de akár majdnem lehetne is, hiszen a programomban ki tudom olvasni, hogy milyen adattáblák vannak, Az adattáblákban szereplő mező neveket is meg lehet tudni. Na persze ez még kevés a boldogsághoz. De a többi szükséges adatot valahol egy plusz adattáblában eltárolom.

Mint mondtam, azt majd megoldom. Nem erre van most szükségem, hanem a dialógus kreáló osztályra.

Jujj, micsoda eretnekseg ;)

Igen, a javan kivuli vilagban ez igy mukodik, hogy lehet dinamikusan letrehozni tipusokat :)

Foleg ha az uzleti logika kimerul a letrehozas-listazas-egyedi nezet - modositas -torles sokszogben (CRUD)

Pl. egyes CMS rendszerek a csuunya buta PHP-ban ugy mukodnek, hogy nem az SQL tipusrendszerevel dolgoznak, hanem egy urlaporientalttal, es van egy dialogustervezo UI, magan a CMS-en belul. Amikor elmentesz egy uj adatformatumot, general hozza egy XML leirot, az XML-bol egy SQL-t (vagy ORM osztalyt,attol fugg epp melyik) es keresre letrehozza a tablat, voila :)

A vilagon nincs megegy olyan rendszer a javan kivul, ami fejlesztoi igenyek helyett elvi meg flamerigenyeket akarna kielegiteni..

Na igen. UI -> DB irányba. De szerintem épp az ellenkezőjét szeretné.

Ezen azt értem, hogy a dialógusokat nem fixen előre gyártanám le, hanem a program futásakor adnánk meg, hogy mi legyen bennük. Pl. vehetnénk egy adatbázisból, hogy milyen elemekre van szükség, azokat milyen speciális feltételekkel kell előállítani, stb...
Tehát ha a DB-ben azt mondom, hogy alter table és hozzáadok egy oszlopot (=mert egy új elemre van szükség), akkor az alter table utasítás kiadása után nekem aztán működjön és ott legyen az UI formon és minden XML-ben/akármiben, hogy hozzáaadtam egy oszlopot a táblához, mert nem szeretnék kódban túrni egy dekányit se.
Vagy én értem nagyon félre? Ez esetben akkor csak a saját fantáziámból építgetem a hülyeségeimet. :)

Lehet hogy a topic letrehozo meg nem jott ra, hogy nem az SQL-nek kene lennie a megfelelo absztrakcios szintnek ;)

De pl. lattam mar SQL editorokat, amik dinamikusan letrehoztak a formot a tablaadattipusok alapjan - hogy ne menjunk nagyon messzire, ilyen az MS Access vagy a phpmyadmin.

Szerintem neki annyi kellene, hogy dinamikusan tudjon letrehozni egyszeru rekord-szeru tipusokat, amibol tetszoleges mennyiseget eltarolhat, meg egymassal tartalmazas, esetleg N-M kapcsolatban tudjanak allni; SQL az, amiben szamara ez trivialis de ha ehhez editor (=> masik absztrakcios szint) kene, az se gond gondolom.

Szoval a feladat egyaltalan nem lehetetlen, csak ralatas kerdese :)

Lehet hogy a topic letrehozo meg nem jott ra, hogy nem az SQL-nek kene lennie a megfelelo absztrakcios szintnek ;)
Na ja, de ő az adatbázisból szeretné legyártani a formokat. Én egyelőre azt próbálom felfogni, hogy mit is szeretne. :)

lattam mar SQL editorokat, amik dinamikusan letrehoztak a formot a tablaadattipusok
Az is rendben van, hogy létrehoznak formot táblaadattípusok alapján. De ő ezt úgy szeretné megspékelni ráadásul, hogy egy másik tábla rekordjait felhasználva alkalmazna rá megszorításokat.

Majdnem jól érted. A kódot nem akarom turkálni egy új űrlap miatt. Úgy akarom megcsinálni, hogy az adatbázis adminisztrátor mindenféle Java programozási ismeretek nélkül képes legyen karbantartani a rendszert. Ennyi lenne a lényeg.

Ebben viszont tévedsz:

Tehát ha a DB-ben azt mondom, hogy alter table és hozzáadok egy oszlopot (=mert egy új elemre van szükség), akkor az alter table utasítás kiadása után nekem aztán működjön

Ez még szerintem is kivitelezhetetlen. Mondtam már. Egy segéd táblázatban meg szeretném adni, hogy milyen adatbeviteli módon jelenjen meg. Milyen vizsgálatokat kell az adatokon végrehajtani (min-max érték, stb... ). És ezek ismeretében gyártanám le a dialógust.

Nem nyakatekert ez, csak egyedi igény. Anno én is csináltam SWT-hez XML-alapú dialog libet: deklarálhattad a mezőket típusokkal (choice, binary, string, file lett implementálva), plusz hozzá validációkat (min, max, length, regex és ezek logikai műveletekkel összekötve), majd ebből generált egy SWT dialogot szépen ügyesen.
Szerk. és tudott összefüggéseket is, azaz ha pl. az A chioceból az X elem lett kiválasztva, akkor a B elem required ( és enabled) lett, és ilyenek.

Nyakatekert abban az értelemben, hogy nem szeretne hozzányúlni a kódhoz, de ez meg így akkor valószínűleg egyedi igény lesz, amihez meg kódot kell fejleszteni (ami azért nem 2 perc lesz, ha rendesen meg akarja írni), ami vagy támogat majd mindent, vagy ha nem, akkor ahhoz a kódhoz kell hozzányúlni módosítás esetén, ami generálja. Szóval ez olyasmi, amikor olyat szeretnék, amihez semmit nem kell csinálnom, de olyannal, amihez mindent nekem kell csinálnom.

Azon gondolkodok, hogy felesleges ehhez xml-t irni.
Egy jol megannotalt modelbol ki lehet indulni. Sot, meg az sem kell, reflekcioval ki lehet olvasni egy modellbol, hogy az adott mezoje milyen tipusu. Azt kell esetleg megannotalni, hogy mely mezokhoz _nem_ kell ui elem. A relaciokat is egyszeru osszeszedni, foleg, ha a db modelljeid mogott JPA van, az egy egesz jo konvenciot tesz kotelezove.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal 

Ez még szerintem is kivitelezhetetlen. Mondtam már. Egy segéd táblázatban meg szeretném adni, hogy milyen adatbeviteli módon jelenjen meg. Milyen vizsgálatokat kell az adatokon végrehajtani (min-max érték, stb... ). És ezek ismeretében gyártanám le a dialógust.
Tehát minden az adatbázisban van, form adatai, típusai, alkalmazandó megszorítások, minden. Rendben.
Ha legyártottál egyszer egy formot, akkor az módosulhat a továbbiakban? Ha nem, akkor legyártod egyszer és nem kell a kódban turkálnod. Ha igen, akkor mit csinálsz? Legyártod újra a dialógust? Ez a "legyártás" különben is mit jelent és mivel jár?

Arra meg már inkább nem is reagálok, hogy adatbázis adminisztrátornak kell...

1. Az XML file létrehozható futásidőben is, vagyis megadható futásidőben is.
http://metawidget.sourceforge.net/doc/api/org/metawidget/config/ConfigR… ő felel a beolvasásáért.
A leírós XML csak opcionális amúgy is. Ha DBvel dolgozol, akkor ajánlom a JPA Inspectort, DB-ben létező modellekből építi fel a dialógusokat: http://metawidget.sourceforge.net/doc/api/org/metawidget/inspector/jpa/…
2. Igen, kell annyi kódot írnod, hogy hol van a DB, hol vannak az entitások, majd az átadott entitásosztály alapján generáljon egy dialógost. Miért kéen minden űrlap hozzáadásakor kódhoz nyúlni? Ha gondolkodnál, hamar rájönnél egy egyszerű dinamikus megoldásra.
3. Igen, alapesetben ez így van, de ez konfigurálható. Olvass tovább :) Ha érted az architektúrát, akkor tudod, hogy a WidgetBuilderek felelősek az UI felépítéséért, őket kell konfigurálni.

Megnézem a linkjeidet!

Miért kéen minden űrlap hozzáadásakor kódhoz nyúlni? Ha gondolkodnál, hamar rájönnél egy egyszerű dinamikus megoldásra.

Nem tudom. Esetleg lehet pl. egy ArrayList típust is megadni adattagnak? És annyi stringet pakolok bele, amennyi jól esik? Vagy valami hasonló trükk? Viszek fel rengeteg fölösleges adattagot, és ezek közül annyit jelenítek meg, amennyi kell? (Láttam egy ilyen paramétert: hidden="true")

Nem Java, de talán segít: a DevExpress-nek van egy ilyen komponense: http://www.devexpress.com/Products/NET/Controls/WinForms/Vertical_Grid/ . Egyébként nem olyan bonyolult ez, hogy 3rd party megoldás kelljen rá. SELECT, beolvasod egy hashtáblába, UI-ban létrehozod egy táblázatban a sorokat, aztán hashtáblából UPDATE/INSERT. És ezt meg lehet csinálni típusosan, metavezérelten, akár úgy is, hogy az adatbázisból vagy a SELECT eredményéből olvasod ki a mezők neveit, típusait. Nézd meg, hogy működik egy phpPgAdmin, bármilyen táblaszerkezethez generál neked formokat. Vagy a Visual Studioban egy property editor: az is egy vertical grid, a metaadatokat meg reflectionnel szedi ki. A lényeg, hogy megértsd ezeket, aztán te is össze tudod rakni.

--
joco voltam szevasz