Kategória: Python gyerekeknek.
Table of Contents
|
Áttekintés
Idáig csak parancssori utasításokat tanultunk. Ahhoz, hogy a Scratch-hez hasonló játékokat tudjunk készíteni, meg kell ismerkednünk a grafikus felhasználói felület programozásával. Ez több szempontból sem annyira nyilvánvaló, mint a Scratch-ben:
- A Pythonban (és ez igaz majdnem minden programozási nyelvre) a grafikus felhasználói felület használatának a mikéntje nem egyértelmű. A legtöbb esetben egy olyan könyvtárat kell használnunk, ami alapból nem is része a nyelvnek. Ezekből ráadásul többféle lehet.
- Itt nincs vászon, nincsenek szereplők, nincsenek jelmezek, nincs rajzasztal sem, és olyan műveletek sem léteznek, mint pl. az, hogy egy szereplő érint-e egy másik szereplőt. Ezt mind nekünk kell megvalósítanunk.
Ugyanakkor a legtöbb grafikus felület tudása messze több, mint amit a Scratch-ben megismerünk, csak nem áll kézre. Mi most a TK grafikus felülettel ismerkedünk meg, ami a Pythonban a legelterjedtebb, és része az alap telepítésnek. Teljes egészében nem fogjuk megismerni, épp hogy csak a felszínét karcoljuk majd, amely elegendő lesz ahhoz, hogy egy játékot elkészítsünk.
Egy egyszerű ablak
Lássunk egy egyszerű példát!
from tkinter import * root = Tk() root.mainloop()
Ennek az eredménye egy üres ablak:
A kód magyarázata:
- from tkinter import *: a könyvtár, amit használni fogunk, az a tkinter. Innen mindent betöltünk.
- root = Tk(): ezzel létrehozunk egy fő ablakot. A Tk egy osztály. A root ennek az ablaknak a neve. Ez bármi lehet. Megszokott a root elnevezés, ami azt jelenti angolul, hogy gyökér. De adhatnánk neki más nevet is, pl. window (ablak).
- root.mainloop(): enélkül parancssorból indítva nem működik; az IDLE szerkesztőből egyébként enélkül is működik.
Összetettebb ablak
Példa
Lássunk most egy összetettebb példát!
from tkinter import * def button_click(): name = str(name_entry.get()) if name != '': greeting_label['text'] = f'Szia, {name}!' root = Tk() name_frame = Frame(master=root) name_label = Label(master=name_frame, text='Név:') name_label.grid(column=0, row=0) name_entry = Entry(master=name_frame) name_entry.grid(column=1, row=0) name_frame.pack() button = Button(master=root, text='Kattints rám!', command=button_click) button.pack() greeting_label = Label(master=root, text='Hello!') greeting_label.pack() root.mainloop()
Ennek az eredménye:
Ilyen grafikus elemek nincsenek a Scratch-ben. De nem egyszerű! Nézzük sorról sorra!
- from tkinter import *: ezt már láttuk.
- root = Tk(): ezt is.
- name_frame = Frame(master=root): egy ún. keretet hozunk létre. Angolul a frame szó keretet jelent. Ez is egy osztály. Azt láthatjuk a fenti példába is, hogy az elemeket egymás alá helyezi; ezzel azt fogjuk megmondani a programnak, hogy a név feliratot, és a bevitel mezőt (ahova beírjuk a nevünket) ne egymás alá, hanem egymás mellé tegye.
- name_label = Label(master=name_frame, text='Név:'): egy feliratot hozunk létre ezzel. A label szó szerint címkét jelent. Ennek két paramétert adunk át név szerint: az egyik a master, melynek megmondjuk, hogy mihez tartozik. A name_frame az a keret, amit az imént létrehozunk. A text maga a felirat.
- name_label.grid(column=0, row=0): ezzel azt mondjuk meg, hogy a név címke pontosan hol szerepeljen a kereten belül. A grid szó szerint rácsot jelent: azt adjuk meg, hogy a rács hányadik oszlopában (column) és hányadik sorában (row) kerüljön. Az oszlopokat és a sorokat is 0-tól sorszámozzuk. Ez a keret egy soros lesz, aminek tehát 0 a sorszáma. Az oszlop is 0, tehát ez lesz bal oldalon.
- name_entry = Entry(master=name_frame): az entry beviteli mezőt jelent, ide a felhasználó be tud írni valamit. Megadjuk, hogy ez is a korábban létrehozott keretre kerüljön.
- name_entry.grid(column=1, row=0): a felirathoz hasonlóan ennek is megadjuk a koordinátáját a rácson. Ez eggyel jobbra kerül, mint a név felirat.
- name_frame.pack(): ezzel tesszük láthatóvá a keretet, ill. ezáltal mindazt, ami rajta van. A pack azt jelenti, hogy becsomagol, ami arra utal, hogy itt határozza meg a pontos méretét.
- button = Button(master=root, text='Kattints rám!', command=button_click): a button nyomógombot jelent. Ez közvetlenül rákerül a fő ablakra.
- button.pack(): láthatóvá tesszük a nyomógombot is.
- greeting_label = Label(master=root, text='Hello!'): az a felirat, ahol üdvözli a program a felhasználót. Ez is közvetlenül a fő ablakra kerül.
- greeting_label.pack(): ezt is láthatóvá tesszük.
- root.mainloop(): ezt már láttuk; néha kell.
Most láttuk a button_click részt:
- def button_click():: függvényt hozunk létre a szokásos módon.
- name = str(name_entry.get()): a name_entry a beviteli mező neve. Ezzel a sorral kiolvassuk az oda beírt értéket, és értékül adjuk a name változónak.
- if name != '':: csak akkor változtatjuk meg a felirat értékét, ha a beírt név nem üres; itt ezt ellenőrizzük.
- greeting_label['text'] = f'Szia, {name}!': így tudjuk egy címkének átírni a szövegét.
Még számos grafikus elem létezik: rádiógombok, kiválasztó elemek, többsoros beviteli mezők stb.; ezekre hely- és időszűke miatt nem térünk ki. Egyet viszont részletesebben meg kell néznünk: a vásznat, angolul canvas. Ez az, ami leginkább hasonlít a Scratch felületre.
from tkinter import * root = Tk() canvas = Canvas(master=root, width=480, height=360, bg='white') canvas.pack() root.mainloop()
Lássuk az ismeretlen sorokat:
- canvas = Canvas(master=root, width=480, height=360, bg='white'): itt hozzuk létre a vásznat, és állítjuk be az alapértékeit. Ennek nagyon sok adatmezője és függvénye van. A paramétereket nézzük meg részletesebben:
- master=root: közvetlenül a fő ablakra kerül.
- width=480: szélesség 480 képpont, mint a Scratch-ben. Itt nem -240-től megy 24 -ig, hanem 0-tól 480-ig.
- height=360: magasság 360 képpont, mint a Scratch-ben. Itt szintén 0-tól megy 360-ig, ráadásul fentről lefelé haladva, ellentétben a Scratch-csel, ahol lentről felfelé haladunk, -180-tól 180-ig.
- bg='white': a háttérszínt beállítjuk fehérre. (A white angolul fehéret jelent.)
- canvas.pack(): megjelenítjük a vásznat
Feladat
Készítsük el az egy kérdéses kvíz játékot grafikus felületen!
from tkinter import * def button_click(): answer = str(answer_entry.get()) if answer == 'Budapest': check_label['text'] = 'A válasz helyes!' else: check_label['text'] = 'A válasz helytelen; a helyes válasz Budapest lett volna.' root = Tk() question_frame = Frame(master=root) question_label = Label(master=question_frame, text='Mi Magyarország fővárosa? ') question_label.grid(column=0, row=0) answer_entry = Entry(master=question_frame) answer_entry.grid(column=1, row=0) question_frame.pack() button = Button(master=question_frame, text='Válasz', command=button_click) button.grid(column=2, row=0) check_label = Label(master=root, text='') check_label.pack() root.mainloop()
Önálló feladat
Bővítsük ki a kvízt tetszőlegesen több kérdésesre, többféle válaszlehetőségre (pl. számot kelljen beírni, több válaszlehetőségből lehessen kiválasztani egyet vagy akár többet stb.).
Vászon
Példa
A következő már egy egészen összetett példa lesz: kirajzolunk egy kört, és mozgatjuk is:
from tkinter import * def key_pressed(event): circle_coord = canvas.coords(circle) if event.keysym == 'Left' and circle_coord[0] > 5: canvas.move(circle, -5, 0) if event.keysym == 'Right' and circle_coord[0] <= 455: canvas.move(circle, 5, 0) if event.keysym == 'Up' and circle_coord[1] > 5: canvas.move(circle, 0, -5) if event.keysym == 'Down' and circle_coord[1] <= 335: canvas.move(circle, 0, 5) root = Tk() root.title('Mozgatás') canvas = Canvas(master=root, width=480, height=360, bg='white') canvas.pack() circle = canvas.create_oval(230, 170, 250, 190, width=3, outline='black', fill='yellow') root.bind('<KeyPress>', key_pressed) root.mainloop()
Eredmény:
Először lássuk a főprogram ismeretlen sorait!
- circle = canvas.create_oval(230, 170, 250, 190, width=3, outline='black', fill='yellow'): ezzel hozunk létre a vásznon egy kört. Valójában olyan oválist rajzolunk, amelynek a szélessége és a magassága is megegyezik. Az első 4 szám annak a képzeletbeli téglalapnak a bal felső ill. jobb alsó x és y koordinátája, melynek képzeletbeli éleit az ovális érinti. A width a körív vastagsága képpontban, az outline a körív színe (black = fekete), a fill pedig annak kitöltése (yellow = sárga).
- root.bind('<KeyPress>', key_pressed): ezzel mondjuk meg azt, hogy mi fusson le akkor, ha lenyomunk egy billentyűt. Ez a key_pressed() nevű függvény, amit lent megvizsgálunk részletesen.
A key_pressed() függvény sorai:
- def key_pressed(event):: paraméterként magát a kiváltó esemény részleteit kapja meg (event = esemény).
- circle_coord = canvas.coords(circle): a canvas a vászon változó neve, ld. a canvas = Canvas(…) sort lejjebb. A canvas.coords(circle) a vászonra rajzolt kör aktuális koordinátáit adja vissza, mégpedig a képzeletbeli körbe rajzolt négyzet bal felső képpontjáét. Ezt elmentjük a circle_coord változóba.
- if event.keysym == 'Left' and circle_coord[0] > 5:: itt azt ellenőrizzük, hogy egyrészt a lenyomott billentyű a bal nyíl-e (event.keysym == 'Left'), másrészt az x koordináta (ezt jelenti a [0] index) nagyobb-e, mint 5. Itt azt vizsgáljuk, hogy ha még balra lépne, akkor kiférne-e.
- canvas.move(circle, -5, 0): a canvas.move() utasítással tudjuk mozgatni a megadott objektumot (circle). A másik két paraméter azt mutatja, hogy mennyivel változzon az x és az y koordináta. Ebben az esetben az x koordináta -5-tel változik, azaz 5-tel balra lép, míg az y koordináta 0-val változik, azaz nem változik.
- if event.keysym == 'Right' and circle_coord[0] <= 455:: itt azt vizsgáljuk, hogy a lenyomott billentyű a jobbra nyíl-e, ill. az x koordináta eléri-e a 455-öt. Ez a 455 úgy jött ki, hogy a vászon 480 pont széles, ebből lejön az átmérő (20 képpont), valamint az, hogy ha még jobbra lépnénk ötöt, akkor kiférne-e.
- canvas.move(circle, 5, 0): az x koordináta 5 képpontnyit változik, azaz jobbra lépünk.
- if event.keysym == 'Up' and circle_coord[1] > 5:: a felfelé nyíl kezelése, felfelé lépéssel. Figyeljük meg az [1] indexet: ez az y koordinátára vonatkozik.
- canvas.move(circle, 0, -5): léptetés felfelé.
- if event.keysym == 'Down' and circle_coord[1] <= 335:: a lefele nyíl vizsgálata.
- canvas.move(circle, 0, 5): léptetés lefelé.
Scratch-ben ez sokkal egyszerűbb:
Most lássuk hogyan tudunk képet megjeleníteni! Töltsünk le egy png formátumú képet a netről, pl. ezt: https://freepngimg.com/png/13523-smiling-face-with-sunglasses-cool-emoji-png. Átméreteztem, hogy elférjen, és át is neveztem; ezt is lehet használni:
from tkinter import * root = Tk() canvas = Canvas(root, width=480, height=360, bg='white') canvas.pack() emoji_sunglasses_image = PhotoImage(file='emoji_sunglasses.png') emoji = canvas.create_image(240, 180, image=emoji_sunglasses_image) root.mainloop()
Eredmény:
Ez Scratch-ben jóval egyszerűbb, mivel ott a beépített szereplők között is többnyire van megfelelő.
Feladat
Mozgassuk a képet!
from tkinter import * def key_pressed(event): emoji_coord = canvas.coords(emoji) if event.keysym == 'Left' and emoji_coord[0] > 50: canvas.move(emoji, -5, 0) if event.keysym == 'Right' and emoji_coord[0] <= 430: canvas.move(emoji, 5, 0) if event.keysym == 'Up' and emoji_coord[1] > 50: canvas.move(emoji, 0, -5) if event.keysym == 'Down' and emoji_coord[1] <= 310: canvas.move(emoji, 0, 5) root = Tk() root.title('Mozgatás') canvas = Canvas(master=root, width=480, height=360, bg='white') canvas.pack() emoji_sunglasses_image = PhotoImage(file='emoji_sunglasses.png') emoji = canvas.create_image(240, 180, image=emoji_sunglasses_image) root.bind('<KeyPress>', key_pressed) root.mainloop()
Önálló feladat
Mozgassunk egyszerre két képet: az egyiket a nyilakkal, a másikat pedig az A, S, D és W billentyűkkel.
Teszt
1. feladat
A fenti kódokban többek között az alábbiak szerepelnek:
- Label
- Entry
- Button
Programozástechnikailag mik ezek és hogyan használjuk?
A Alap nyelvi elemek, amelyeket "csak úgy" használunk.
B Függvények, amelyeket meghívunk.
C Osztályok, amelyeket példányosítunk.
D Egy másik programozási nyelv elemei, amit kölcsönveszünk.
2. feladat
Az alábbiak közül mi NEM jellemző minden grafikus felületre?
A A TK importálása.
B Grafikus elemek.
C Elrendezések.
D Eseménykezelés.
3. feladat
Mit csinál az alábbi kód?
from tkinter import * Label(text='Név:') name_entry = Entry() Button(text='Kattints rám!') Label(text='Hello!')
A El sem indul, hibát ír ki, mert ez egy helytelen kód.
B Elindul, majd egyből leáll, hibát viszont nem ír ki.
C Megjelenik egy üres ablak, de nem történik semmi.
D Rendben megjelennek a megadott grafikus elemek.