Hogyan készítsünk Excel táblához hasonló számolótáblát? – 2.rész

Az előző bejegyzésben egy Excelszerű egyszerű számolótábla készítését kezdtük el az ott megadott specifikáció alapján. A megvalósítást három fő részre bontottuk, amelyből az elsőt, vagyis a táblázat kirajzolását, valamint az egyes cellákban levő beviteli mezőkhöz tartozó kontrollváltozók létrehozását, már megtettük. Ebben a részben a specifikáció szerinti eseményeket határozzuk meg és kötjük a beviteli mezőkhöz.

A legalapvetőbb esemény az, amikor egy cellába beírt képletnek (kifejezésnek) ki kell értékelődnie, ha Entert nyomunk, vagy a celláról a fókusz elkerül. Ez két eseményt jelent, amelyek bármelyikének hatására egy olyan eseménykezelőnek kell lefutni, amely az eseménnyel érintett cella beviteli mezőjének tartalmát kiértékeli. Legyen ennek neve eval_cell_content_even_handler.

Tehát az Enter megnyomása esetén az esemény és eseménykezelő összerendelése logikailag ez: „Enter billentyű megnyomás” -> eval_cell_content_even_handler.

Ha pedig az adott beviteli mező elveszíti a fókuszt, akkor az esemény és eseménykezelő összerendelés logikailag ez lesz: „Fókuszból kikerülés”-> eval_cell_content_even_handler

Egy beviteli mező akkor kerül ki a fókuszból, ha vagy a Tab billentyűt nyomjuk meg, vagy az egérrel egy másik cellába kattintunk. Mivel létezik a fókuszból kikerülés „FocusOut” esemény, ami egy beviteli mezőre is értelmezhető, ezért nem kell a Tab vagy egy eltérő cellába való kattintást külön lekezelni.

Bár az eseményeket a táblázat összes cellájában levő beviteli mezőjéhez kell kötni, de nem kell külön minden egyes beviteli mezőhöz külön hozzárendelni az eseményeket és az arra reagáló eseménykezelőket, hanem elég egyszer, amennyiben nem a példányokhoz, hanem azok osztályához, az Entry osztályhoz kötjük. Ezt a bind_class() metódussal tehetjük meg, amelyet a gyökérelemre (főablak) hívunk meg. Az előbb említett két eseményre így:

Az is szerepel előírásként, hogy az Enter megnyomásakor a kurzor a cellából az alatta levő cellába kell, hogy átmenjen. Az „Enter lenyomása” eseményhez tehát pluszban még egy olyan eseménykezelőt is kell rendelni (legyen ennek neve move_cursor), amely a kurzort átteszi az alatta levő cellába, vagy ha nincs olyan, akkor a jobbra mellette levőbe. Ha az sincs, akkor pedig a cellában hagyja és nem viszi sehová. Ezt az eseménykezelőt szintén minden beviteli mezőhöz kötni kell, ezért a fentiekhez hasonló módon tesszük:

Az add paraméter True értékre állításával jeleztük, hogy nem az előző eseménykezelő helyett akarjuk a move_cursor-t, hanem azon felül kívánjuk hozzáadni. Ez azt jelenti, hogy az Enter lenyomására először az eval_cell_content_even_handler kerül meghívásra, után pedig a move_cursor.

Még mindig nem szakadhatunk el az ‘Return’ és ‘FocusOut’ eseményektől. Ugyanis ezek bekövetkezésekor, és az előbb említett eseménykezelők lefutása után, a táblázat összes képletét aktualizálni kell, vagyis újra ki kell őket értékelni. Ehhez egy update_expressions nevű eseménykezelő függvényt fogunk bevetni, amely minden egyes beviteli mezőn végigmegy, és ha van benne képlet, akkor kiértékeli azt. Ennek megfelelően a két eseményre az eseménykezelő hozzárendelése így fest:

Az add paraméter beállítása a fentebb már említett okból történik. Most már végeztünk a ‘Return’ és ‘FocusOut’ eseményekkel.

Meg kell még oldani azt, hogy ha a cellában kétszer kattintunk, akkor jöjjön elő a cella értékét meghatározó képlet, ha volt ilyen. Tehát az összerendelendő esemény és eseménykezelő sémája a „Dupla balegérgomb kattintás”-> reveal_cell_expression_event_handler. Az utóbbi nevű eseménykezelő azt fogja tenni, hogy az eseménnyel érintett cella sor- és oszlopindexei alapján kikeresi az ebx_vars nevű szótárból (ld előző bejegyzésben) a karakterláncként tárolt képletet (ha van), és azt megjeleníti a beviteli mezőben. Ebben az esetben a beviteli mezőket, az eseményt és eseménykezelőt összerendelő kód ez:

Azt is szeretnénk, hogy a Del (delete) gomb hatására a cella tartalma és a mögöttes képlet (ha volt) törlődjön. Ehhez a „Del gomb lenyomás” eseményhez az on_delete nevű eseménykezelőt rendeljük. Ez az ebx_vars szótárban az eseménnyel érintett beviteli mező kontrollváltozójának értékét és a képletet üres karaktersorra állítja. A beviteli mezőket, az eseményt és eseménykezelőt összekötő kód ebben ez esetben így néz ki:

És végül azt is szeretnénk, hogy ha a jobb egérgombbal duplán kattintunk egy cellán, akkor az adott oszlop szélessége úgy változzon, hogy az oszlop cellái közül a leghosszabb szöveg is látszódjon. Ez a hosszabb képletek áttekinthetőségét nagyban segíti. Ezt a fit_column_width nevű eseménykezelő fogja megvalósítani. Az esemény-eseménykezelő kód az alábbi, ahol, mint eddig is, az eseményt az összes beviteli mezőhöz egyszerre rendeltük hozzá.

A fentiekben említett, az eseményeket és eseménykezelőket a beviteli mezőkhöz kötő kódsorokkal kiegészített programkód a következő:

A következő bejegyzésben már az eseménykezelő függvények megvalósításával foglalkozunk.

E bejegyzéshez kapcsolódóan a Python tudásépítés lépésről lépésre című e-könyvben elsősorban a „Grafikus felhasználói felület készítése” fejezetben az „Események és programkód összerendelése” című alfejezetet érdemes tanulmányozni.

É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.