Tkinter alapok 1. rész

A számítógépek otthoni vagy munkahelyi felhasználása napjainkban alapvetően desktop alapú, mind windows mind linux alapú desktopok esetében pedig az alkalmazások nagyon nagy hányada valamilyen grafikus felületről kezelhető, ezt nevezzük GUI-nak, azaz grafikus felhasználói felületnek (Graphical User Interface).
Kedvenc pythonunk tartalmaz egy modult GUI felületű programok készítésére, neve Tkinter.

A Tk a Tcl (Tool Command Language) programnyelvhez kapcsolódik szorosan, annak GUI készlete tulajdonképpen. A Tk widgetek (ejtsd: vidzset, window gadget azaz ablak kütyü) minden platformon - windows, mac, unix, linux - natívan, azaz a legtermészetesebben néznek ki, és erősen használják a gazdarendszer elemeit és lehetőségeit.
A Tkinter modul tulajdonképpen egy Tcl interfész, dióhéjban a Tkinter modul Tcl parancsokká konvertálja a python parancsainkat és azzal hívja meg a C-ben megírt tkinter modult, ami előállítja a megfelelő grafikus objektumokat a gazdarendszer segítségével.

Evezzünk gyakorlatiasabb vizekre, nézzünk egy egyszerű 'Helló világ!' példát:

#!/usr/env/python
# -*- coding: utf-8 -*-

from Tkinter import *

class Application():
    def say_hi(self):
        print "Helló világ!"

    def createWidgets(self):
        self.QUIT = Button(self.frame,text="Kilépés",command=self.frame.quit)
        self.QUIT.pack({"side": "left"})

        self.hi_there = Button(self.frame, text="Helló világ!",command=self.say_hi)
        self.hi_there.pack({"side": "left"})

    def __init__(self, frame):
        self.frame=frame
        self.frame.title("Helló világ Tk")
        self.createWidgets()

root = Tk()
app = Application(root)
app.frame.mainloop()
root.destroy()

Minden Tk alapú python programban be kell importálnunk a Tkinter modult (4. sor). Az esetek többségében az import * from módszert használjuk, hiszen a sok GUI elemhez jónéhányszor le kéne írnunk a 'Tkinter'-t. Ha a Tkinter elemek ütköznek mással, akkor sajnos az import Tkinter változatot kell használnunk.
Ez után következik az alkalmazásunk fő osztálya (Application osztály), de ezt most ugorjuk át, nézzük előbb a 22-25 sorokat.
A 22. sorban egy root változóhoz hozzárendeljük a Tk osztály egy példányát, amely az alkalmazásunk szülő keretét fogja alkotni. A Tk alapú GUI felületek elemeit mindig egy másik Tk keretbe kell illeszteni, kivéve a szülő keretet, vagy másnéven gyökér keretet.
A 23. sorban példányosítjuk az alkalmazásunkat az app változóban, majd elindítjuk az alkalmazás fő ciklusát (mainloop) a 24. sorban. Ez addig dolgozik, amíg egy Tk quit parancssal ki nem lépünk belőle. Ekkor a 25. sorban felszabadítjuk a root változót, és befejeződhet a program.

Lássuk az Application osztályunkat!
A createWidgets() metódus létrehoz két gombot, egy Kilépés feliratút és egy Helló világ feliratút, majd ezeket elhelyezi a gyökérkeretben.
A Button widgeteknek két lényeges paraméterük van, a rajtuk megjelenő felirat, amit a text argumentummal tudunk a Button konstruktorának átadni, és a gomb megnyomásakor végrehajtandó függvény vagy metódus, amit command argumentumban adunk át. Itt az osztályunkban található say_hi metódust adtuk meg. Figyeljük meg, hogy zárójelek nélkül került megadásra, ami esetünkben azt jelenti, hogy nem a say_hi metódus végrehajtását kérjük a pythontól, hanem a say_hi függvényobjektumot rendeljük a command paraméterhez.
Ez a függvény mindössze a "Helló világ!" sztringet írja ki standard kimenetre, azaz a terminálba, ha onnan indítjuk. Ha nem terminálból indítjuk, akkor ugye nem fogjuk látni a karakteres kimenetet.
Az osztályunk __init__ metódusa beállítja az argumentumként kapott frame-et osztályváltozóként, címet ad a szülőkeretnek, amit az ablakkezelők meg tudnak jeleníteni az ablak címsávjában, és meghívja a createWidgets metódust, ami létrehozza az előbbiekben megtárgyaltak szerint az ablak elemeit.
Ennyit a Tk alapokról! Tessék kísérletezni, olvasni és kérdezni :)

5 megjegyzés:

  1. Helló!
    Jó a bevezetés, igaz én sokkal jobban csípem a Qt-ot, igaz még pythonnal nem használtam. Sajnos ha jól tudom a Tkinter csak GNOME-ba integrálódik jól, KDE-be nem.

    Van esély Qt-os cikkekre?

    VálaszTörlés
  2. Szia, igen, lesz majd Qt is, ha egyszer odaérek :)
    A Tk-nak viszont semmi köze egyik GUI toolkithez sem, ezektől teljesen független, így gyakorlatilag mindegyik alatt egyformán működik, ráadásul a python terjesztések minden OS-hez tartalmazzák, így teljesen multiplatformos GUI-s alkalamazást tudunk vele alkotni anélkül hogy a usernek más dolgokat is fel kéne telepíteni.
    A Qt sokkal magasabb szintű toolkit mint a Tk, ezért természetesen gazdagabb felületű progit lehet vele készíteni, de a Tk-nak is megvannak az előnyei.

    VálaszTörlés
  3. szia:)

    3.2-es python alatt tkinterben van arra mód hogy:

    egy ablakban külön-külön minden adatbeviteli objektumra (szövegesek érdekelnek főleg pl: entry) enter vagy tab vagy egérkattintásra minden objektumra egyéni függvényhívás történjen meg?

    VálaszTörlés
  4. Nem tudom hogy 3.2 alatt változott-e a dolog, de eddig lehetett egy objektumra is eseményt bindelni, tehát self.myentry1.bind('',self.myentry1_katt) kell hogy működjön

    VálaszTörlés
  5. még csak most tanulom mélyebben a pythont eddig csak kisebb szöveg(html)feldolgozás, fájlműveletek adatbázis kezeléseket csinálgattam... nyúlfarknyiakat...semmi grafikus felület... ezt kifejtenéd ha megkérlek itt hogy bindeljem rá egy billentyű lenyomásra hogy hogy mi legyen (és egy mezőre lehessen többfajta billentyűlenyomás is vagyis jó lenne:) ? kb így néz ki most a programrész - ez is adatbázis-kezelés féleség... http://pastebin.com/SJ1MBy93


    class bszamla(tkinter.Toplevel):

    def __init__(self, parent):
    super().__init__(parent)
    self.parent = parent
    self.accepted = False
    self.transient(self.parent)
    self.title("Számlák")
    self.nameVar=''
    wszamla = tkinter.Frame(self)

    self.adatdb=adatkezel.Database('proba9')
    self.mezolista=self.adatdb.tableFieldsName('a01_fejlab')
    sor=0
    self.ertek={}
    for mezo in self.mezolista:
    exec(mezo+'=None')
    exec(mezo+'Label = tkinter.Label(wszamla, text=mezo, underline=0)')
    exec(mezo+'Entry = tkinter.Entry(wszamla, textvariable=mezo)')
    exec(mezo+'Label.grid(row=sor, column=0, sticky=tkinter.W, pady=3,padx=3)')
    exec(mezo+'Entry.grid(row=sor, column=1, columnspan=3,sticky=tkinter.EW, pady=3, padx=3)')
    sor+=1

    exec(mezo+'Entry.focus_set()')

    okButton = tkinter.Button(wszamla, text="Ok", command=self.ok)
    cancelButton = tkinter.Button(wszamla, text="Mégsem",command=self.close)


    okButton.grid(row=sor, column=2, sticky=tkinter.EW, pady=3,padx=3)
    cancelButton.grid(row=sor, column=3, sticky=tkinter.EW, pady=3,padx=3)

    wszamla.grid(row=0, column=0, sticky=tkinter.NSEW)
    wszamla.columnconfigure(1, weight=1)
    window = self.winfo_toplevel()
    window.columnconfigure(0, weight=1)

    #self.bind("", lambda *ignore: mezoEntry.focus_set())

    self.bind("", self.ok)
    self.bind("", self.close)

    self.protocol("WM_DELETE_WINDOW", self.close)
    self.grab_set()
    self.wait_window(self)


    def ok(self, event=None):
    for mezo in self.mezolista:
    self.ertek.update([(mezo,eval(mezo))])
    print(self.ertek)
    self.adatdb.recAdd('a01_fejlab',self.ertek)
    self.accepted = True
    self.close()


    def close(self, event=None):
    self.parent.focus_set()
    self.destroy()

    VálaszTörlés