Galéria véletlen sorrendben

Adott egy mappában lévő sok-sok képfájl, többféle formátumban, kiterjesztéssel. A feladat az, hogy időzítve jelenítsük meg ezeket a képeket véletlen sorrendben saját fejlesztésű Java program segítségével. A tervezés során áttekintünk többféle lehetőséget. Bemutatjuk a megoldáshoz szükséges lépéseket és a program működését.

A program tervezése

A szükséges bemeneti adatok

  • Egy mappa, abszolút vagy relatív útvonal, ahol a képfájlok megtalálhatók. A mappa átvehető a program paramétereként (ha parancssorban meghívva átadjuk) vagy lehet az aktuális mappa (ahonnan a programot jar fájlként elindítjuk). A program a mappában közvetlenül megtalálható képeket olvassa be. Az ott található almappákba nem megy bele.
  • A képfájlok különböző kiterjesztéseit tárolni kell. Többféle is lehet, így ehhez szükséges alkalmas adatszerkezet. A listában nem szereplő kiterjesztéssel rendelkező fájlok nem kerülnek feldolgozásra.
  • Érdemes a képfájlokat egy lépésben betölteni a memóriába. Így a program takarékos erőforrásként bánik a tárhellyel (merevlemez, pen-drive, SSD, hálózati meghajtó). Csak egyszer dolgozza fel (olvassa végig) a mappát. Feltételezzük, hogy a képfájlok beférnek a memóriába.
  • A program teljes képernyős, amiből elérhető a rendelkezésre álló terület mérete, ahol megjeleníthetők a képek. A program a betöltött képfájlok méreteihez is hozzáfér. Ez a méret kétféle lehet: bájtban kifejezhető a képfájl elfoglalt tárhelye, illetve pixelben kifejezhető a képfájl dimenziója (másképpen a megjelentéséhez szükséges terület mérete a képernyőn).

Hogyan működik a program?

  • Egyszerre egy kép jelenik meg. Időzítő befolyásolja a képfájlok közötti váltást. Meghatározza, hogy a képfájlok meddig látszanak (másképpen: eltelt idő, késleltetés, várakoztatás). A swing GUI-hoz tartozó időzítőt kell hozzá használni.
  • A program alkalmazkodik a képernyő, kijelző felbontásához, képarányához. A program végtelenítve működik, Alt + F4 billentyűkombinációval lehet kilépni belőle.
  • A képfájlok megjelenítésük során optimálisan, dinamikusan kitöltik a rendelkezésre álló téglalap alakú területet. A túl kicsi képeket nagyítani kell. A túl nagy képeket kicsinyíteni kell. Mindezt úgy, hogy a képarányt (aspect ratio) meg kell tartani, hogy a képek ne torzuljanak el. Az alábbi három példa balról-jobbra mutatja az optimális kitöltést, illetve azt a két esetet, ami akkor történik, amikor a kép méretéhez képest a megjelenítésre használható terület túl magas vagy túl széles:
  • A galériába tartozó képek közötti véletlen sorrendet meg kell oldani. A program a memóriába betöltött képek sorszámai alapján valósítja meg a véletlenszerű kiválasztást. A sorszámok összekeverednek. Egymás után nem jöhet ugyanaz a kép többször. Ha a képek „elfogynak”, akkor a program végtelenített működése szerint a képek sorszámai újra összekeverednek és „lejátszásra kerülnek”.

A program megvalósítása

A mappát a java.io csomag File osztályából létrehozott folder objektum tárolja (a "./"  szövegliterál jelöli az aktuális mappát). A feldolgozandó képfájlok kiterjesztéseinek listáját egy dinamikus tömbből létrehozott generikus lista oldja meg: ArrayList<String> imageFileExtensionList=new ArrayList<>(Arrays.asList("JPG", "JPEG", "PNG", "GIF")). Egy képfájl memóriabeli tárolását a  java.awt.image.BufferedImage típus valósítja meg, amelyekből szintén generikus lista épül: ArrayList<BufferedImage> imageList. A grafikus felhasználói felülethez tartozó javax.swing csomagbeli Timer osztály szükséges, például 2 mp-es várakoztatás és eseménykezelés: timer=new Timer(2000, (ActionEvent) -> { showRandomImage(); }). A GUI JFrame leszármazott keretobjektum. A grafikus felhasználói felület a teljes képernyőt elfoglalja: setExtendedState(MAXIMIZED_BOTH) és setUndecorated(true). A keretre egyetlen JLabel típusú, fekete hátterű lbImage objektum kerül, az alapértelmezett határmenti elrendezésmenedzser közepére (vízszintesen és függőlegesen egyaránt). A képfájlok sorszámai (a későbbi véletlen kiválasztáshoz) az imageIndexList generikus listába/kollekcióba kerülnek. Az index változó jelöli az aktuális, memóriába betöltött képfájl sorszámát, ami kezdetben nulláról indul.

A képfájlok betöltése az alábbiak szerinti:

A fájlok kiterjesztésének szűrése a FileFilter interfész accept() metódusának megvalósításával történik. A fenti forráskódban mindez tömör, lambda kifejezéssel (művelettel) valósul meg. A fájlszűrőn az képfájl megy át, aminek a nagybetűssé alakított kiterjesztését tartalmazza az  imageFileExtensionList kollekció. Az i-edik képfájl memóriába való betöltését az ImageIO osztály statikus read() függvénye oldja meg. A képfájlok sorszámainak véletlen összekeverése kezdetben megtörténik: Collections.shuffle(imageIndexList). A fájlkezelés miatt kötelező kivételkezelést most – itt a szakmai blogban – nem részletezzük.

Az időzítő eseménykezelése, a 2 másodpercenkénti képváltás így valósul meg:

A program alábbi metódusa felel a képarányhoz kötődő műveletekért:

A program tesztelése

  • Érdemes lehet tesztelni nem ajánlott (rossz) megoldásként azt, hogy a program az időzítőnek megfelelően, dinamikusan olvasná be a képfájlokat, amivel lényegesen kevesebb memóriát igényelne.
  • Van-e reális korlát arra, hogy mennyi, mekkora képek „férnek el” a memóriában?
  • Hogyan befolyásolja a képfájlok száma és az általuk elfoglalt tárhely a program indulását?
  • Mi történik, ha nincs megfelelő kiterjesztésű képfájl a mappában? És ha több 1000 kép van benne?
  • Hogyan jelennek meg (megjelennek-e) az animációt tartalmazó képfájlok? Például a GIF képformátum nem csak statikus egyetlen képet tartalmazhat, hanem lehet animált is.
  • Teljesen megvalósul-e a reszponzivitás? Ha igen, mi indokolja? Ha nem, miért nem és hogyan lehetne megoldani?

Ha átmenetileg kikapcsoljuk a teljes képernyős megjelenítést, akkor könnyen tesztelhetővé válik a megvalósuló reszponzivitás. Másképpen a program dinamikusan alkalmazkodik a rendelkezésre álló (rajzolható) terület méreteihez (szélesség és magasság):

A program továbbfejlesztési lehetőségei

  • A program rekurzívan bejárhatná a folder által megjegyzett útvonalból kiindulva a teljes (al)mappaszerkezetet.
  • A program paraméterezhető lehetne a képfájlok kiterjesztéseivel. Akár konfigurációs fájlból is beolvashatná az imageFileExtensionList adatszerkezetet, például XML, JSON formátumban is.
  • A program ellenőrizhetné, hogy a mappában lévő összes kép befér-e a memóriába. A program kezelhetne ehhez kötődően többféle limitet: például az első 100 db képet töltené be, és/vagy csak annyi képet tölt be, ami belefér például 64 MB-ba.
  • A program mutathatná folyamatindikátorral induláskor a képfájlok betöltését. Vagy betölthetné például az első 5 db-ot és háttérszálon a többit, amíg az első 5-öt „lejátssza”.
  • Ha például a program 10 képet tölt be mappában lévő képfájlokból, akkor ezek 0-tól 9-ig sorszámozódnak. A sorszámok összekeverve következnek. Ha az első menetben az utolsó kép sorszáma például a 7 volt, akkor a következő ismétlődő menet nem kezdődhetne 7-tel.
  • A programból ki lehetne lépni az Esc billentyűvel is. KeyListener interfésszel megoldható.
  • A program kezelhetne egyéb képfájlformátumokat is: például animált GIF, statikus WebP, animált WebP.
  • A program könnyen kiegészíthető prezentációk diáinak időzített/felülbírált megjelenítésére.
  • A program által beolvasott képfájlokból generálható PDF fájl is (rácsos sablonnal, például 6 db kép laponként). A feldolgoztt mappában lévő képfájlok könnyen feltölthetők FTP szerver adott mappájába, átméretezhetőek csoportosan, elküldhetők nyomtatási sorba is.
  • Érdemes megismerni a JDK-n kívüli egyéb, képfájlokat kezelő osztályok, csomagok funkcióit, például: OpenIMAJ, TwelveMonkeys ImageIO.
  • A swing-es felület kiegészíthető mappatallózással, egyéni fájl(típus)szűrőkkel, paraméterezhető lehet a véletlenszerű kiválasztás algoritmusa, változtatható az időzítés késleltetése.
  • Mivel a program teljes képernyős, így elrejthető az egérmutató.
  • A képek „lejátszásából” lehetne generálni animált GIF-et.

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 Java SE szoftverfejlesztő tanfolyamunkon, a szakmai modul Objektumorientált programozás témakörét követő 29-36. óra Grafikus felhasználói felület alkalmain már tudunk egyszerűbb animációs, szimulációs programot tervezni, kódolni, tesztelni.

Beszámoló: it-tanfolyam.hu STEM nyári tábor 2023

A STEM mozaikszó eléggé közismert: a tudományos-technológiai tudományágakat (természettudomány, technológia, mérnöki tudomány és matematika) foglalja egybe, interdiszciplináris megközelítésben. A STEM területén való elmélyedés során a hangsúly nem a mit tanulunk/tanítunk, hanem inkább a hogyan tanulunk/tanítunk. Nem azonnal ad kézzel fogható válaszokat, de kitartó próbálkozással – saját élménnyel – elérhető az eredmény.

Az it-tanfolyam.hu oktatói csapata 2023-ban először hirdetett STEM nyári tábort. Erről számolunk be röviden ebben a blog bejegyzésben. Tervezzük, hogy a jövőben rendszeresen fogunk szervezni STEM nyári tábort.

A STEM nyári tábor koncepciója

2023. nyarán 4 turnusban hirdettünk programozás fókuszú STEM nyári tábort:

  • 1. turnus: július 3-7-ig,
  • 2. turnus: július 10-14-ig,
  • 3. turnus: július 17-21-ig,
  • 4. turnus: július 24-28-ig.

Előzetes tudás- és igényfelmérést végeztünk, így alakítottunk ki 3 db csoportot, ezek: Java kezdő, Python kezdő, Python haladó. A kiinduló célcsoportot tanfolyamaink karrierváltó hallgatóinak gyermekei jelentették, akik mellé toboroztunk még. A korosztály a 16-20 éves diákok voltak a 11-14. évfolyamról. A 11-12. évfolyamosok közül sokan informatika, digitális kultúra érettségi előkészítő fakultációra jelentkeztek, jártak, járnak és ebből érettségiznek/érettségiztek. A már korábban érettségizett 13-14. évfolyamosok körülbelül fele az OKJ utód szakmajegyzékhez tartozó szakképzésben tanult.

Mindegyik turnus azonos tematikával valósult meg. Turnusonként 3 db párhuzamos, 10-12 fős csoportokat indítottunk. Voltak közös elméleti programok, szakmai kirándulás, illetve külön-külön Java és Python nyelven megvalósuló gyakorlati programok, valamint projektbemutatóra is sor került. Igyekeztünk érinteni sokféle STEM területet: fizika, kémia, biológia, csillagászat, térinformatika, mesterséges intelligencia, szimuláció, játékprogramok, matematika, orvostudomány; mindegyiket a programozáshoz kapcsolva. Végeztünk tervezést, kódolást, tesztelést is. Belefért némi pályaorientáció is.

A STEM nyári tábor órarendje

Turnusonként 4 oktató kollégával és vendégelőadókkal hétfőtől-péntekig minden nap 8 és 18 óra között biztosítottuk a jelenlétet, felügyeletet. 40 órában szakmai programokat (elmélet+gyakorlat) kínáltunk. Reggelenként és késő délutánonként 1-1 órában offline, egyéni vagy csoportos játékok voltak kipróbálhatók. Ez mindösszesen 50 órát jelentett. Délelőttönként 20, 30 és 60 perces programokat terveztünk, délutánonként 120 és 240 perceseket. Szerdára szakmai kirándulást, gyárlátogatást ütemeztünk be. Íme az órarend áttekintő formában:

Íme az órarend naponként lapozható formában, benne a részletekkel:

Előzetes tapasztalataink

Előzetes tapasztalatainkat több forrásból merítettük, inspirálódtunk:

Köszönetnyilvánítás

Köszönjük résztvevő diákjainknak az aktivitást, a lelkesedést, a sok-sok elgondolkodtató kérdést, az offline kapott/szerzett élményeket, a pozitív visszajelzéseket.

Szeretnék köszönetet mondani együttműködő partnereinknek: LEGO Manufacturing Kft., REGIO Játékkereskedelmi Kft., Revolt Kereskedelmi Kft., Pannon Kincstár Humán Szakképző Központ.

Végül szeretnék köszönetet mondani minden oktató kollégámnak konstruktív részvételüként, kitartásukért a projekt teljes életciklusában. A tervezési, a szponzorszerző, a promóciós és a megvalósítási szakaszokban egyaránt 2023. április elejétől július végéig. Kiemelem korábbi és az aktuális projekthez kötődő tananyagfejlesztési tevékenységüket. A sikeresen lezárt projektünket augusztusban kipihenjük. 😉

Digitális Témahét 2023

A Digitális Témahét 2016-ban indult országos rendezvénysorozat. Fő célja, hogy a digitális eszközökkel támogatott projektpedagógia és innovatív pedagógiai módszerek terjesztésén keresztül. A program fontos törekvése, hogy a digitáliskompetencia-fejlesztés az informatikán túl kiterjedjen más tantárgyakra is. A résztvevő pedagógusok és diákok változatos és kreatív iskolai projektek keretében fejleszthetik képességeiket technológiával támogatott tanulás során. A Digitális Témahét rendezvény minden meghirdetett programja ingyenes. A 2021/2022-es tanévben 811 hazai és külhoni intézmény regisztrált, és 115 ezer tanuló vett részt egy vagy több programon, digitális projektben.

A 2022/2023-as tanévben a rendezvény március 27-31. között valósult meg. Kiemelt témák:

  • digitális állampolgárság;
  • a digitalizáció jelene és jövője;
  • a technológia eszközei és alkalmazásai;
  • az algoritmikus gondolkodás és programozás mint az alkotás eszközei;
  • digitális biztonság és digitális esélyteremtés.

Rendezvényünk plakátja

Az it-tanfolyam.hu 2023-ban is csatlakozott a rendezvénysorozathoz. Oktatóink meghirdettek hét programot, amelyekre 2023. március 31-én 18:00-21:00 óráig került sor.

Köszönöm oktató kollégáimnak, hogy örömmel csatlakoztak. A résztvevőinknek is köszönjük, hogy ellátogattak hozzánk. Mindannyian jól éreztük magunkat: közel 40-en voltunk jelen személyesen és online is közel 30-an követtek bennünket. Igazán tartalmas programot állítottunk össze. Valódi flow-élményt jelentett. Tanfolyamunk hallgatói és az érdeklődők számára is tudtunk újat mutatni. A programok közötti szünetek lehetőséget adtak a kérdésekre, az ismerkedésre. A kiállított posztereink körül is többször alakult ki csoportosulás, kötetlen beszélgetés. Idén is szívesen csatlakoztunk a rendezvénysorozathoz és szívesen emlékszünk majd vissza rá.

Egy példányban futó Java program

egy

egyGyakran észrevesszük, hogy a programok futtatásakor vannak bizonyos korlátok. Például egyszerre általában csak egyetlen telepítőprogram futhat egy operációs rendszeren. Vagy amíg fut egy program korábbi verziójának eltávolítása, addig nem futhat a program új verziójának telepítője. Vagy egy nagyobb erőforrás igényű program (periféria meghajtó program, képernyő videó+hang rögzítő, hardveres gyorsítást használó játékprogram) egyszerre csak egy példányban indítható el. Előfordulhat kategóriánkénti korlát is, például a különböző víruskereső programok általában „nem tűrik meg” egymást, kizárólagosságot „követelnek”.

Lássunk példát arra, hogyan kell készíteni egy példányban futó Java programot!

Néhány dolgot át kell gondolni:

  • Amikor először indítjuk el a programot, akkor olyan egyedi dolgot kell beállítani, ami mindvégig úgy marad, amíg a program fut. Ezt megtehetjük a memóriában, de megfelelő jogosultsággal futtatva a programot akár beleírhatunk a Windows rendszerleíró adatbázisába (Registry) is. Előbbi módszer platformfüggetlen lenne – ahogyan egy Java programhoz illik –, és az utóbbi megoldás pedig operációs rendszertől függne.
  • Amikor többedszer (második, harmadik… példányban) indítjuk el a programot, akkor ezt az egyedi dolgot észlelni kell és meg kell akadályozni a program másodszori, harmadszori elindítását. Hasznos, ha ezekben az esetekben kapunk hibaüzenetet, például: „This application is already running”.
  • Amikor a programot szabályosan állítjuk le, akkor a korábban beállított egyedi dolgot semmissé kell tenni. Ez biztosítja, hogy a program egymás után – egymással nem párhuzamosan, egymástól függetlenül – elindítható lesz.

A megoldás két részből áll. Ez a Java forráskód első része:

A program indulásakor le kell futni a fenti forráskódnak. A static blokk a konstruktor előtt hajtódik végre (például a modell vagy a nézet rétegben). A java.net csomag kötetlen ServerSocket osztályú ss nevű objektumát kell inicializálni helyben ( InetAddress.getLocalHost()) egy nem dedikált porttal ( 65001). Ez elsőre mindig sikerült és az objektum „beül a memóriába” egy nem blokkoló elven működő háttérszálon. Ha (többedszerre) nem sikerül létrehozni az objektumot, akkor – kezelve a kötelezően kezelendő kivételeket – hasznos jelezni ezt logban, konzolon vagy felbukkanó párbeszédablakban és a programból ki kell lépni (másképpen: a duplikált futtatását meg kell akadályozni).

Ez a Java forráskód második része:

A programból való szabályos kilépéskor le kell futni a fenti forráskódnak. Ez ellenőrzést követően lezárja az ss objektumot és kilép a programból. Például a main() metódusban, ha elfogynak az utasítások egy konzolos alkalmazásban, vagy GUI-s programban nyomógombra kattintás actionPerformed() esemény, vagy (fő)ablak bezárásának kísérlete WindowClosing() esemény.

A programot érdemes körültekintően tesztelni. Ha elrontjuk a fenti felsorolásban vázolt logikai működés végrehajtásának sorrendjét, akkor fejlesztés vagy tesztelés közben akár a számítógépet is újra kell indítanunk.

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 Java EE szoftverfejlesztő tanfolyamunkon, a szakmai modul 5-8. óra Szálkezelés, párhuzamosság alkalommal megismerjük a megoldás elméleti hátterét és a 17-24. óra Socket és RMI alapú kommunikáció alkalommal többféle megvalósítást is kódolunk, tesztelünk.

Rómeó és Júlia

Vajon hogyan kerül elő a Rómeó és Júlia az it-tanfolyam.hu szakmai blogban témaként? Hiszen mégiscsak egy Shakespeare színműről/tragédiáról van szó. Vajon mit programozhatunk Java nyelven ehhez kötődően épp Valentin-napon? Mindjárt kiderül.

Tegyünk fel egy kérdést és próbáljunk rá válaszolni! Vajon ki szereti jobban a másikat? Rómeó vagy Júlia?

Induljunk el az adatforrásból, amihez alkalmazkodnunk kell. A színmű angol nyelven publikusan elérhető XML formátumban: The Tragedy of Romeo and Juliet. Az XML fájlok könnyen feldolgozhatók Java nyelven. Részletek a fájlból (görgethető):

Az XML fájl felépítését tanulmányozva (1-5 alapján) megállapíthatóak az alábbiak:

  • A színmű öt felvonásból áll, ezeket <ACT></ACT> csomópontok jelölik.
  • Egy „adagnyi” beszédet a <SPEECH></SPEECH> csomópont fog össze.
  • A csomópontban található, hogy ki beszél: ez a <SPEAKER></SPEAKER> elem. A mesélő, kar esetén ez az elem üres, és a null-t nem szabad feldolgozni.
  • A csomópontban találhatók a szabadvers kimondott sorai: ezek a <LINE></LINE> elemek. Legalább egy sor minden beszédben van, és nem tudjuk előre a számukat.
  • Nem következetes helyen a DOM-ban, többféleképpen beágyazva és önállóan is előfordulhatnak <STAGEDIR></STAGEDIR> elemek. Ezek a színmű Kosztolányi-féle magyar fordításában dőlt betűvel megjelenő – cselekvésre utaló – színpadi utasítások. Van köztük csók is, amit az XML-ből nem szabad feldolgozni, bár erősen ráutaló magatartás. 🙂
  • Nem tudjuk előre, hogy hány csomópont található a fájlban.

A Java program készítése, tesztelése közben – mintegy mellékesen – megtudhatjuk, hogy Rómeó 612 sorban 24075 betűnyi, Júlia 544 sorban 21855 betűnyi szöveget mond. Persze nem mindet egymásnak mondják. Eközben vajon hányszor mondják ki a szeret, szeretem, szeretlek szavakat? A ragoktól, toldalékoktól, kis- és nagybetűket nem megkülönböztetve és attól is eltekintve, hogy éppen kinek/kiknek mondják amit éppen mondanak, egy becsléshez elegendő, ha a love szóra fókuszálunk (számíthatna a loving alak is).

Az alábbi Java forráskód betölti az XML fájlt a memóriába. Ezután kiválogatja a beszédeket. Ha a beszélő élő ember (szereplő), akkor érdekes, hogy mit/miket mond. Ha ROMEO vagy JULIET mondja az adott sort, akkor azt a program kiválogatja két generikus listába ( romeoLineList és julietLineList) beszédnyi adagokban. Ez nem szétválogatás programozási tétel, mert nem minden beszéd minden sora kerül valahová. A kivételkezelés nem kidolgozott.

Könnyen megkaphatjuk, hogy Rómeó hány darab olyan sort mond, amely tartalmazza a love szót. Például ennek a lambda kifejezésnek kiíratva az eredményét a konzolra:

Könnyen megkaphatjuk Rómeótól a 53 sornyi szöveget is így:

Íme Rómeó kiválogatott sorai (az 5. sorban kétszer is előfordul a love, de ez most nem számít):

Hasonlóan megkaphatjuk Júlia 38 kiválogatott sorát is:

Próbáljunk válaszolni a fentiek alapján a feltett kérdésre! Következtethetünk arra, hogy Rómeó jobban szereti Júliát. Legalábbis többször említi. 53>38. Persze tudjuk, hogy mindez nem ilyen egyszerű. 🙂

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.

Nagyon különböző megoldásokat készíthetünk és szerteágazóan gyakorolhatunk, ha:

  • az XML fájlt kézzel mentjük a webről és utána a helyi fájlrendszerből dolgozzuk fel,
  • az XML fájlt közvetlenül a webről, dinamikusan olvassuk,
  • csak beépített XML-feldolgozást használunk,
  • külső XML API-t használunk,
  • DOM, SAX, XSL, van-e DTD,
  • XPath kifejezésekkel adunk választ a kérdésre,
  • a fenti didaktikusan egyszerű megoldás helyett haladóbb eszközöket (például: Stream API-t) használunk.