Hogyan készítsünk KRESZ táblákat rajzoló programot? – 3.rész

Az előző bejegyzésben odáig jutottunk a közlekedési tábla rajzoló programunk fejlesztésében, hogy a ProhibitorySign osztály példánya – amely egyben egy konkrét KRESZ tábla is – reagál az egérgörgővel vagy bizonyos billentyűkombinációkkal kiváltott eseményekre, amelyek hatására a kirajzolt tábla mérete változtatható.

Most innen lépünk tovább, és egy osztályt fogunk készíteni, amelyek példányai olyan tiltó táblák, amelyek közepén valamilyen szövegesen megjeleníthető információ helyezkedik el. Ilyenek tipikusan a sebességkorlátozó táblák. Ezért az új osztály neve SpeedLimitSign lesz.

Ezt a SpeedLimitSign osztályt a ProhibitorySign osztály alosztályaként definiáljuk. Ezzel azt érjük el, hogy a tábla körformája a piros szegéllyel rendelkezésre áll, vagyis ennek kódolásával nem kell foglalkozni. Összesen annyit kell csak megoldani, hogy a kívánt szöveg megjelenjen a tábla közepén.

Ezen felül a ProhibitorySign osztályból történő öröklés azt is biztosítja, hogy az új osztály példányai is reagálnak majd a fent említett eseményekre, és így a tábla méretét ezekkel tudjuk változtatni.

Ez utóbbi állítás igaz ugyan, de az öröklés csak azt biztosítja, hogy a körtábla (pontosabban a külső és belső körök), valamint a vászon mérete változzon az eseményekre. Az új táblák közepén megjelenő szöveg méretét ezekkel egyelőre nem tudjuk változtatni. Ez természetes is, hiszen a ProhibitorySign mint szülőosztály nem tartalmazott semmilyen információt és kódot szöveges rajzelem, vagy más grafikus objektum méretének változtatására.

A feladat tehát, hogy

1) elhelyezzük a kívánt szöveget (számot) a SpeedLimitSign példányok közepén,

2) biztosítsuk azt, hogy a szöveg mérete a tábla átméretezésekor arányosan változzon, persze megőrizve a középre helyezett pozícióját.

Az első feladat elvben nem túl nehéz, mert csak annyit kell tenni, hogy a SpeedLimitSign __init__ metódusában argumentumként a példányosításkor bekérjük a kiírandó sebességlimit számot, majd létrehozunk egy szöveges rajzelemet a vászonra (amit ugye most a self reprezentál) meghívott create_text() metódussal. Ennek első argumentumaiként a szöveg középpontjának koordinátáit kell megadni, ami jelen esetben a körök közös középpontja lesz, ami az öröklés révén rendelkezésre áll. A create_text() metódus text parméteréhez rendeljük a bekért számot szövegként, a font paraméterhez pedig egy számunkra szimpatikus betűtípust rendelünk. Ezt a tkinter.font csomag beimportálása után a Font osztállyal határozzuk meg. Ebben a betűtípuscsaládot (pl. Arial, Calibri stb) karakterláncként a family paraméterrel kell megadni. Ha akarjuk, megadhatjuk a weight paraméterrel, hogy a betű félkövér legyen. Jelen esetben élünk ezzel a lehetőséggel. Be lehetne állítani, hogy dőlt vagy áthúzott legyen a betű, de a feladatunk szempontjából ezek most nem relevánsak.

Izgalmas kérdés viszont a betűméret megadása, amit a Font konstruktorának size paraméteréhez kell rendelni egész számként.

Ha előre ismert méretű lenne a táblánk, és az nem is változna, akkor könnyű dolgunk lenne, mert a belső kör átmérőjét figyelembe véve meg tudnánk választani azt a megfelelő betűméretet, amellyel a szöveg nem lóg ki a körből, de nem is túl kicsi. De most nem ez a helyzet, mert nem tudjuk előre a kezdőméretet, és ráadásul a tábla méretét futási időben is bármikor változtathatjuk. Ehhez kell a szöveg méretének mindig igazodnia.

A nehézség ott van, hogy – ellentétben pl. a körökkel – a szöveg rajzelem méretét (beleértve a betű nagyságát) nem lehet szélesség és magasság értékek megadásával változtatni. A szöveg méretét valójában az alkalmazott betűtípus aktuális mérete szabja meg. Ezért nem tudunk más tenni, mint kezdetnek a legkisebb betűmérettel indulunk, ezzel hozzuk létre a szöveg rajzelemet, majd egy megfelelő saját készítésű, _fit_text_size() nevű metódussal addig növeljük a betűméretet, amíg az megfelelő nem lesz az éppen aktuális táblamérethez.

Az eddig elmondottak kódban a SpeedLimitSign __init__ metódusában követhetők alább:

És ezzel át is kerültünk a fenti 2) feladathoz. Vagyis ahhoz, hogy hogyan valósítjuk meg hogy a szöveg, illetve annak betűmérete megfelelő legyen.

Elsőnek meghatározzuk, hogy mi az a maximális méretű terület, amelyet a szöveg rajzelem által foglalt terület nem léphet túl. Ehhez előállítjuk a belső kör befoglaló négyzetének koordinátáit. Mivel ez a belső kört kívülről határolja, ez még túl nagy lenne megengedhető területnek. Ezért ebből kiindulva egy olyan négyzet koordinátáit állítjuk elő, amelynek területe nem, vagy nem nagyon nyúlik túl a belső kör területén. Ez lesz tehát az a négyzet, amelyen a szöveg nem lóghat túl.

Ezt követően a szöveg rajzelemet a legkisebb betűméretű betűtípussal konfiguráljuk. Ez lesz a kiindulás. Utána egy ciklusban addig növeljük a betűméretet és végezzük el a betűtípus és szöveges rajzelem újrakonfigurálását, amíg annak mérete nagyobb nem lesz a fentebb meghatározott redukált négyzet méreténél. Amikor ez bekövetkezik, akkor leállunk a betűméretnöveléssel.

Ezen elvek megvalósítását látjuk a _fit_text_size() metódus törzsében.

Ezzel még csak a példányosítás utáni kezdeti szövegméret beállítását végeztük el. De, arról is kell gondoskodni, hogy méretváltoztatást kezdeményező esemény hatására megváltozó táblamérethez is igazodjon a szöveg rajzelem mérete.

Az átméretezést végző eseménykezelők (lásd előző bejegyzésben) a körök sugarát változtatták a set_radius() metódus segítségével. Ezt kell tehát felülírnunk az új SpeedLimitSign osztályban úgy, hogy elsőként meghívjuk a szülőosztály azonos nevű metódusát, amivel a körök mérete fog megváltozni. Miután ez megtörtént, rendelkezésre állnak az új körök, azok méretei, valamint az új középpont koordinátái. Ez utóbbit felhasználva a vászon példányra meghívott coords() metódussal újra pozícionáljuk a szöveg rajzelemet. Ezt követően a fentebb ismertetett _fit_text_size() metódussal az új helyzethez igazítjuk a szöveg rajzelem méretét. Ezeket a lépéseket láthatjuk a set_radius() definíciójában.

A tesztfuttáshoz a teljes kód így néz ki:

A teszt során három sebességkorlátozó táblát hoztunk létre azonos kezdeti mérettel, majd egérgörgővel eltérő nagyságú táblákká alakítottuk azokat. Ezt az állapotot mutatja ez a képernyőkép:

A következő bejegyzésben olyan tiltó táblákat fogunk készíteni, amelyek közepén valamilyen képi tartalom (piktogram) van. Ezek képezik a KRESZ tiltó tábláinak többségét. Itt is elsősorban a méretezés jelent majd némi kihívást.

E bejegyzéshez kapcsolódóan a Python tudásépítés lépésről lépésre című e-könyv „Grafikus felhasználói felület készítése” fejezetének alábbi alfejezeteiben találunk részletes információkat: „A grafikus elemek fajtái, létrehozásuk és konfigurálásuk” – „Vászon” alcím és abban a szöveg rajzelem. Továbbá az „Osztály vigyázz! – típuslétrehozás osztályokkal”, és „Öröklődés” fejezetek.

Érdekel a Python tudásépítés lépésről lépésre az alapoktól az első asztali alkalmazásig című e-könyv.