Fát építünk

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.

Péntek 13

Péntek 13

Péntek 13Sokan szerencsés vagy balszerencsés napnak tartják a péntek tizenharmadikát. Évente 1-2-3 alkalommal megtörténik, hogy a hónap 13. napja péntekre esik (minden vasárnap kezdődő hónapban). A hónap 13. napja valamivel valószínűbben péntekre esik, mint a hét bármely más napja. Átlagosan 212,35 naponként fordul elő péntek 13. Előfordulhat két egymást követő hónapban is, de akár 14 hónap is eltelhet két péntek 13 között.

A nap említése sok helyen előfordult: regényekben, filmekben, híres emberek születése vagy halála is esett péntek 13-ra. Átlag alatti közlekedési baleset szokott előfordulni ezeken a napokon – talán mert az emberek óvatosabbak. Kimutatható összefüggést/korrelációt, „péntek 13 hatást” figyeltek meg a tőzsdén is.

Hasznos lehet, ha írunk egy Java programot, amely néhány egymást követő év esetén listázza a konzolra azokat a hónapokat, amikor 13-a péntekre esik.

Tervezés

Legyen egy listFriday13(year) eljárás, amely a paraméterként átvett évben kiírja azokat a hónapokat a konzolra, amelyekben 13-a péntekre esett/esik. Például: 2017: január, október. A hónapok nevei magyar nyelven jelenjenek meg. Az adott év hónapjain végighaladó ciklus legyen hatékony. Optimalizáljunk a ciklus lépésszámára! A ciklus álljon le, ha már talált 3 hónapot (mivel nem lehet több).

1. megoldás

A megoldást a tematika Tömbök témakörében az alábbiak szerint készíthetjük el. Előismeretek: változók, operátorok, ciklusok, programozási tételek, metódusok, tömbök, String összehasonlítás. Az ismert öröknaptár algoritmusokból implementáljuk az egyiket, például:

A listFriday13v1(year) eljárásban az elemi döntés egyszerű: dayOfWeek(year, month, 13).equals("Friday"). Épít az öröknaptárt megvalósító – saját – szöveget visszaadó függvényre. A függvény az algoritmus szerinti kódok előállításához ( centuryCode, monthCode, dayCode) felhasználja a szökőév ( isLeapYear(year)) függvényt, valamint két – konstansnak is tekinthető – névtelen tömböt ( new int[], new String[]).

2. megoldás

A megoldást a tematika Objektumorientált programozás témakörében az alábbiak szerint készíthetjük el. Felhasználjuk eddigi ismereteinket és a JDK beépített dátumkezelő (tároló, formázó) funkcióit (osztályok, interfészek, konstansok, felsorolások).

A listFriday13v2(year) eljárás a Calendar absztrakt osztály konstansait használja fel az elemi döntéshez: date.get(Calendar.DAY_OF_WEEK)==Calendar.FRIDAY. A dátumot a GregorianCalendar konstruktora példányosítja és figyelni kell a 0-bázisú hónapkezelésre. A dátum formázása során ( dfMonth) beállítjuk a megfelelően paraméterezett ( "hu") Locale típusú objektumot és a hónap hosszú nevét kérjük ( "MMMM"). A metódus generikus listába gyűjti a kiválasztott hónapok nevét, amiket végül a String.join() függvény fűz össze a megjelenítéshez.

Eredmény

A vezérlésben egy ciklus 2017-től 2036-ig szervezve az alábbi eredményt adja:

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 tematikájához kötődik a fentiek szerint: 13-16. óra: Tömbök alkalom, illetve 17-28. óra: Objektumorientált programozás alkalom.

Aki gyakorolna a témához kötődően: írjon olyan Java programot, ami listázza a konzolra a 21. század éveit olyan hónapokba csoportosítva, amikor 13-a péntekre esik. Egy év többször is előfordulhat. Például: január – 2006, 2012, 2017, 2023, 2034, 2040, 2045, 2051, 2062, 2068, 2073, 2079, 2090, 2096. A megoldásokat hallgatóinktól az ILIAS-ra, érdeklődőinktől hozzászólásban várjuk.

Ismerkedjünk lambda kifejezésekkel!

lambda kifejezés logo

lambda kifejezés logoA Java 8-tól használhatunk lambda kifejezéseket, amivel hatékonyabban, rövidebben és könnyebben valósíthatunk meg tipikus műveleteket.

Korábban általában az eseménykezelést globálisan (interfészek implementálásával), vagy lokálisan (névtelen interfész implementálásával) oldottuk meg, illetve besegítettek adapterek is. Sok- és többféle eseménynél ez a forráskódunk elaprózódásához vezetett, ami nehézkes olvashatóságot és karbantarthatóságot eredményezett.

A lambda kifejezés egy olyan kódrészlet, amelyben valamihez hozzárendelünk valamit, például egy metódus paraméteréhez a végrehajtandó forráskódot ( x -> y). Ehhez építünk a funkcionális interfészekre és a metódus referenciákra (szintén Java 8-tól), illetve a típus kikövetkeztetés képességére is (Java 7-től).

A kiválogatás programozási tételt valósítjuk meg többféle implementációval, felhasználva a Java nyelv újdonságait, és a fentieken kívül még a Stream API-t is.

Adatforrás

Először is kellenek adatok, hiszen azokat dolgozzuk fel. Egy Termek osztályú egyszerű POJO-val dolgozunk, nev és ar tulajdonságokkal, generált konstruktorral, getter metódusokkal és toString()-gel. Az adatforrást biztosító absztrakt Lista ősosztályban a POJO-kból felépítünk egy termekLista nevű generikus listát (például CSV vagy XML fájlból beolvasva az összetartozó adatokat) – listaFeltolt() eljárás – és implementálunk egy univerzálisan használható listaKiir(String uzenet, List termekLista) eljárást is.

Örökítünk három utódosztályt a Lista osztályból, amelyek különbözőképpen dolgozzák fel a termekLista-t, bemutatva a fejlődés útját, illetve a rendelkezésre álló lehetőségeket.

Válogassunk a termékek közül négyféleképpen és adjuk vissza azon termékeket, amelyek:

  • limit alatti áron kaphatók,
  • ára limit1 és limit2 közé esik (zárt intervallumban),
  • neve adott szöveggel kezdődik (kis- és nagybetű különbözik),
  • neve adott szöveget tartalmaz (kis- és nagybetű nem különbözik)!

1. változat

Hagyományos megközelítéssel a fentiek megvalósításához külön egy-egy függvény tartozik, ahogyan az alábbiakban látható:

A termekListaLimitAr1() függvényben látható ötféle lehetőség a kiválogatásra a termekLista-ból:

  • //1: hagyományos, index alapú változat,
  • //2: iterátorra közvetlenül építő változat,
  • //3: bejáró ciklus, iterátorra közvetve építő változat,
  • //4: Stream API-ra építő változat, kiválogatás lambda-kifejezéssel ( filter), a megmaradó termékekre végrehajtandó forEach művelet lambda kifejezéssel,
  • //5: Stream API-ra építő változat, kiválogatás lambda-kifejezéssel ( filter), a megmaradó termékeket összegyűjtő/leképező collect művelettel.

Jól megfigyelhető, hogy négy függvény vázszerkezete megegyezik, és csupán a filter-ben található lambda-kifejezések különböznek. Ez a megoldás meglehetősen redundáns, nem általánosítható, valamint további műveletek megvalósítása további függvények implementálását igényli.

2. változat

Őrizzük meg a négyféle funkciót, sőt tegyük lehetővé, hogy ez tetszőlegesen bővíthető legyen. Használjunk saját generikus, funkcionális Feltetel interfészt saját döntés megvalósítását biztosítani tudó implementálandó teszt() függvénnyel, az alábbiak szerint:

A termekListaFeltetel() függvény paramétere a saját Feltetel interfészünket implementáló névtelen osztály példánya, amely felhasználható:

  • //6: ciklusban egyszerű feltételként,
  • //7: Stream API filter műveletében megadott lambda-kifejezésben,
  • //8: a listaKiir() metódusban paraméterként átadva névtelen osztály példányaként,
  • //9-től: a listaKiir() metódusban paraméterként átadva lambda-kifejezésként.

Látszik, hogy többféle kiválogató művelethez egyetlen implementált függvény szükséges. Ez a megoldás már jóval általánosabb.

3. változat

A saját interfész helyett használjuk fel a beépített Predicate generikus, funkcionális interfészt, építve annak test() függvényére az alábbiak szerint:

Belépési pont

Végül következzen a közös belépési pont, amelyben tetszőlegesen aktiválható és tesztelhető mindhárom változat működése:

Mit ír ki a program a konzolra?

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 szakmai moduljának 21-24. óra: Objektumorientált programozás 2. rész, 25-28. óra: Objektumorientált programozás 3. rész, valamint a Java EE szoftverfejlesztő tanfolyam szakmai moduljának 9-12. óra: XML feldolgozás alkalmaihoz kötődik.

Máskor is blogolunk a témakörben: Stream API lambda kifejezésekkel.

Hello World! másképpen

Hello World! - Piet programozási nyelven

Hello World! - Piet programozási nyelvenA programozási nyelvek tanulásának első lépése a „Hello World!” szintaktikájának megismerése, és egyben teszt arra is, hogy megfelelő-e a fejlesztői környezet telepítése, konfigurálása. Megjelenik-e a „Hello World!” a konzolon, felbukkanó ablakban, önálló ablakban, weblapon, üzenetben? Mit kell ezért tenni? Néhány Java példát nézünk erre.

1. Konzolos megoldás

Ez a kiinduló állapot. Futtatva a programot, a konzolon jelenik meg a szöveg.

2. Swing 1. megoldás

Itt felbukkanó párbeszédablakban jelenik meg a szöveg. A JOptionPane ablaka itt önálló, így nincs olyan szülője/tulajdonosa ( null), ahonnan elveheti a fókuszt.

3. Swing 2. megoldás

Itt egy testre szabott JFrame utód készül, alapvető beállításokkal. Az ablak címsorában jelenik meg a szöveg. Az ablak saját magát példányosítja és főablakként viselkedik, vagyis gondoskodik saját maga láthatóságáról, fókusz- és eseménykezeléséről (utóbbi 2 most nincs).

4. JavaFX megoldás

Itt egy testre szabott  Application utód készül, minimál beállításokkal. Az ablak címsorában jelenik meg a szöveg. Az ablak saját magát példányosítja és főablakként viselkedik.

5. Applet megoldás

Böngészőben fut a testre szabott JApplet utód. A weblapon elfoglalt téglalap alakú területen vízszintesen balra és függőlegesen középen jelenik meg a címke komponensben a szöveg.

6. JSP 1. megoldás

Ez egy JSP weboldal automatikusan generált forráskódja. Böngészőben jelenik meg a szöveg.

7. JSP 2. megoldás

Ez egy JSP weboldal egyszerű direktívával a h1 címsorban.

8. Servlet megoldás

Itt egy szervlet által generált weboldal, amely fixen tartalmazza a szöveget.

9. Atipikus 1. megoldás

„Adatbázisból is lekérdezhető” a szöveg.

10. Atipikus 2. megoldás

Ebben az esetben a Java nyelv által biztosított véletlenszám generáló osztályra támaszkodva állítjuk elő a szöveget. Mivel a random objektum által előállított számok csupán a véletlenség látszatát keltik, de valójában egy algoritmus szerint készülnek, ezért előre teljes pontossággal megjósolható a kimenet. Csupán meg kell találni azt a kezdőértéket, ami után „véletlenül” pont a h, e, l, l, o betűk fognak következni. Megismételve a folyamatot egy másik kezdőértékkel, megkapjuk a w, o, r, l, d  betűket is.

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

A példák a Java SE szoftverfejlesztő tanfolyam, a Java EE szoftverfejlesztő tanfolyam és a Java adatbázis-kezelő tanfolyam több alkalmához is kötődnek (kivéve 4. és 5.).

Hivatkozások a témakörben, amelyek más programozási nyelvek példáit is tartalmazzák:

Egy matematika érettségi feladat megoldása programozással 2017

érettségi logó

érettségi logóA 2017-es középszintű matematika érettségi feladatsor 12. feladata inspirált egy Java program megírására. Szükséges hozzá néhány programozási tétel: sorozatszámítás, megszámolás, valamint adatszerkezetként ideális egy kétdimenziós tömb. Érdekes belegondolni, hogy mennyire más lehetne a problémamegoldás, ha programozhatnánk a matematika érettségi vizsgán. A teljes feladatsor a megoldásokkal együtt letölthető az oktatas.hu-ról.

12. feladat

Egy kockával kétszer egymás után dobunk. Adja meg annak a valószínűségét, hogy a két dobott szám összege 7 lesz! Válaszát indokolja!

Matematikai megoldás

A feladat nagyon egyszerű. Két megoldást ismertet a javítási-értékelési útmutató:

  • Összesen 6 * 6 = 36-féleképpen dobhatunk. Hat olyan dobáspár van, amelyben 7 az összeg: (1; 6), (2; 5), (3; 4), (4; 3), (5; 2) és (6; 1). A keresett valószínűség 6/36-od, vagyis egyhatod.
  • Bármennyit is dobunk elsőre, ezt a második dobás egyféleképpen egészítheti ki 7-re. Így a második dobásnál a hat lehetséges értékből egy lesz számunkra kedvező. A keresett valószínűség egyhatod.

Közelítő megoldások szimulációval

Egy alkalom két kockadobást jelent egymás után. A dobások sorrendje nem számít (alkalmanként és összességében sem). Minél több alkalommal végezzük el a kockadobásokat, annál jobban megközelítjük a fenti valószínűséget (várható értéket, bővebben: nagy számok törvénye). Az egyhatod közelítő értéke a Java double adattípusával 0.16666666666666666.

1. megoldás

Ha nem akarunk emlékezni a dobásokra, összegükre, csupán megszámolnánk, hogy hány olyan dobáspár van, amelyben 7 az összeg, akkor ehhez mindössze egy számláló ciklus kell, aminek a ciklusmagjában két véletlen kockadobás összegét előállítjuk és növelünk egy számlálót/gyűjtőt, ha az éppen 7. Az eredményt a számláló és a ciklus lépésszámának hányadosa adja meg. Például meghívhatjuk a metódust így: kockadobas1(5000); és kaphatjuk eredményül ezt: 5000 alkalomból 7 összegként 836 alkalommal fordult elő. Valószínűség: 0.1672 . A metódus kivételt dob, ha értelmetlen a paramétere. Íme a metódus Java forráskódja:

2. megoldás

Ha egy 13 elemű egész típusú tömböt használhatunk emlékezetként. Kezdetben 2-től 12-ig indexelve nullázzuk ki, így csoportos gyűjtést tudunk megvalósítani. A nullázás most inicializáló blokkal történt, mert nem sok eleme van a tömbnek (sok elemnél inkább használjunk erre ciklust). A tömb első két elemét nem használjuk semmire. Mi történik a ciklusban? Például dobas1=3 és dobas2=4 esetén a dobasDbTomb[7] elemét növeli (mindegy mi volt ott korábban, de inkrementálódjon). Most több adatot tárolunk, mint amiből megválaszolható a feladatban megfogalmazott konkrét kérdés, de ezt tekinthetjük strukturális tartaléknak.

Hasonló, egydimenziós tömbbel történő belső adattárolást megvalósító elosztott alkalmazásról blogoltunk már: Kockadobás kliens-szerver alkalmazás.

3. megoldás

Ez az igazi szimuláció, swing GUI grafikus környezetben, ahogyan az alábbi képernyőképen látható. A megvalósítás kétdimenziós tömböt használ adatszerkezetként. Álljon 7 sorból és 7 oszlopból és legyen i a sor- és j az oszlopindex. A tömb [0][0]-dik elemét nem használjuk semmire. Az első oszlopába ( j=0 és i>0) bekerülhetnek a dobókockán előforduló számok 1-től 6-ig. Hasonlóan az első sorba ( i=0 és j>0) is. Ezek a dobott számok alapján indexek lesznek és az ábrán zöld hátterű cellákba kerültek. A tömb többi eleme kezdetben 0 (nulla), ezek az ábrán fehér hátterű cellák. A szürke hátterű cellák (mellékátló) esetén a dobott számok összege 7 és jól látszik, hogy ez hatféleképpen fordulhat elő a 36-féle eset közül. Például a 2. sor 5. oszlopában lévő szám mutatja, hogy a 10000 alkalomból 274-szer fordult elő az, hogy a dobáspár a (2; 5) lett. A tömb két indexe felcserélhető lenne, mert ez a mellékátlóban lévő számok összegét nem befolyásolja.

Kockadobás program képernyőkép

A programban kiválasztható néhány alkalomból amit szeretnénk, és a Dob nyomógombra kattintva indul el időzítővel a folyamat. Várakoztatás/menet közben piros színnel kiemelve látszik/megfigyelhető, hogy az éppen aktuális dobás hol növeli az értéket/előfordulást/darabszámot. A képernyőképen befejeződött állapot látható. Az eredményt a szürke cellákban lévő számok összegének és az alkalmak számának hányadosa adja meg. Ezt a háttérbeli kétdimenziós tömbben összesítéssel az alábbi Java forráskód-részlet adja meg:

Most lényegesen több adatot tárolunk, mint ami a konkrét válaszhoz kell, de cserébe jól érzékeltethető a csoportos gyűjtés/megszámolás működése. A program grafikus felhasználói felületének felépítését és az eseménykezelés megvalósítását most nem részletezzük.

Eszünkbe juthatna, hogy a program miért dob kétszer 1 és 6 közötti számot egymás után és ezt összegzi, amikor egyetlen 2 és 12 közötti dobással (véletlenszám generálással) megkaphatnánk a dobáspár összegét. Hiszen két db 1 és 6 közötti szám összege mindig 2 és 12 közötti szám. Jó lenne ez az ötlet/megvalósítás? Igen? Nem? Miért? A hozzászólásokhoz várjuk az indoklást.

Ajánljuk matematika érettségi feladat címkénket, mert a témában évről-évre blogolunk.

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 szakmai moduljának 17-28. óra: Objektumorientált programozás alkalmaira épülő 29-36. óra: Grafikus felhasználói felület alkalmaihoz kötődik.