79 Kasutajaliidese täiendamine ja nupu tööle panemine
Täiendame nüüd eelmist programmi veelgi. Kohendame välimust selliselt, et:
- Lisame funktsiooni arvuta, mis käivitatakse nupule vajutades. Selleks tuleb nupule lisada parameeter “command = arvuta” ja luua vastav funktsioon arvuta(), kus võetakse meetrite tekstisisestuskastist meetrid, teisendatakse tulemus kilomeetriteks ning väljastatakse kasutajaliideses olevale tekstisildile kilomeetriteks teisendatud tulemus.
- Lisame tekstisiltidele joonduse N, S, E, W, mis joondavad teksti vastavalt ilmakaarele. Näiteks E (east) on paremjoondus ja W (west) on vasakjoondus.
- Viimase asjana lisame komponentide ümber vaba ruumi äärtesse parameetriga padx ja üles ning alla parameetriga pady.
from tkinter import * # tkinteri põhivahendid from tkinter import ttk # platvormi ühise stiili saamiseks def arvuta(): a = str(float(meetrid.get())/1000) kilomeetrid.config(text = a) raam = Tk() raam.title("Meetrite teisendamine") meetrid = ttk.Entry(raam, width=7) meetrid.grid(column=2, row=1, sticky=E, padx=5, pady=5) kilomeetrid = ttk.Label(raam) kilomeetrid.grid(column=2, row=2, sticky=E, padx=5, pady=5) ttk.Button(raam, text="Arvuta!", command = arvuta).grid(column=3, row=3, sticky=W, padx=5, pady=5) ttk.Label(raam, text="meetrit").grid(column=3, row=1, sticky=W, padx=5, pady=5) ttk.Label(raam, text="on võrdne").grid(column=1, row=2, sticky=E, padx=5, pady=5) ttk.Label(raam, text="kilomeetriga.").grid(column=3, row=2, sticky=W, padx=5, pady=5) raam.mainloop()
Töötav teisendusprogramm peaks olema lisatud vahedega selline:
Tkinteri raam raamis
Sageli on kasutajaliidesed veelgi keerulisemad ja koosnevad mitmest sektsioonist. Raami sisse saab lisada omakorda väiksemaid raame, kuhu paigutada komponente. Vaatame ka näidet, kus raami sisse on omakorda paigutatud sisuraam elementidega. Pange tähele, kuidas on sisuraam lisatud omakorda raami!
from tkinter import * # tkinteri põhivahendid from tkinter import ttk # platvormi ühise stiili saamiseks def arvuta(): a = str(float(meetrid.get())/1000) kilomeetrid.config(text = a) raam = Tk() raam.title("Meetrite teisendamine") sisuraam = ttk.Frame(raam, padding="3 3 12 12") sisuraam.grid(column=0, row=0, sticky=(N, W, E, S)) raam.columnconfigure(0, weight=1) raam.rowconfigure(0, weight=1) meetrid = ttk.Entry(sisuraam, width=7) meetrid.grid(column=2, row=1, sticky=(W, E), padx=5, pady=5) kilomeetrid = ttk.Label(sisuraam) kilomeetrid.grid(column=2, row=2, sticky=(W, E), padx=5, pady=5) ttk.Button(sisuraam, text="Arvuta!", command = arvuta).grid(column=3, row=3, sticky=W, padx=5, pady=5) ttk.Label(sisuraam, text="meetrit").grid(column=3, row=1, sticky=W, padx=5, pady=5) ttk.Label(sisuraam, text="on võrdne").grid(column=1, row=2, sticky=E, padx=5, pady=5) ttk.Label(sisuraam, text="kilomeetriga.").grid(column=3, row=2, sticky=W, padx=5, pady=5) raam.mainloop()
Mainisime, et raami sisse saab ka lisada mitu väiksemat raami. Kui on soov näiteks raami lisada sisuraami alla jaluseraam, siis saab seda teha näiteks enne mainloopi käsku selliselt:
jaluseraam = ttk.Frame(raam, padding="5 5 12 12", borderwidth = 2, relief = "sunken")
jaluseraam.grid(column=0, row=1, sticky=(E,W))
ttk.Button(jaluseraam, text="Sulge").grid(column=0, row=0, sticky = E)
Raamile saab ka lisada serva parameetritega borderwidth = 2 ja relief = “sunken” või “raised”.
Nüüd jääb üle vaid lisada ka sulgemise nupule sulgemise funktsionaalsus “command = sulgeprogramm” ja lisada programmi algusesse ka vastava funktsiooni:
def sulgeprogramm():
raam.destroy()
Jaluseraami lisandumisel peaks tulemus olema selline:
Tkinter täiustatud näide raam raamis
Lisaks eelnevale tutvustame paari nippi, kuidas lahendada järgnevaid probleemküsimusi:
- Kuidas kontrollida, kas on tekstisisestuskasti on sisestatud arv?
Tekstisisestuskasti sisestatud sõne kontrollimiseks on mugav kasutada try ja except plokki. Siin programmis saab try-käsuga proovida, kas sisestatud sõne on võimalik teisendada arvuks, et teha soovitud arvutusi. Seda saab teha selliselt:
try:
a = float(meetrid.get())
kilomeetrid.set(a / 1000)
meetrid.set("")
Mis aga juhtub siis, kui kasutaja trükib ebasobiva sõne ja tekib sõne teisendamisel arvuks veateade? Selleks tuleb lisada ka except osa, mis püüab kinni tekkinud veateated. Praegusel juhul siis püütakse kinni veateate ValueError teke:
except ValueError:
kilomeetrid.set("Ei saanud teisendada. Sisesta arv!")
meetrid.set("")
- Kuidas kasutada programmis jooksvalt sõne tüüpi muutujaid?
Selleks, et programmis jooksvalt kasutada erinevaid sõne tüüpi muutujaid, kuhu saaks tekstisisestuskasti trükitud väärtusi salvestada, saame defineerida vastava muutuja käsklusega kilomeetrid = StringVar(). Nüüd saab mugavalt tekstisildil kasutada kuvatava väärtusena kilomeetreid “textvariable=kilomeetrid” ja vastavat teksti tekstisildil muuta käsklusega kilomeetrid.set().
- Kuidas komponentide omadusi korraga muuta?
Näeme, et kõigi komponentide ümber on määratud viiepiksline vaba ruum parameetritega padx ja pady. Kuidas saaks mugavalt muuta kõigi komponentide ümber olevat ruumi? Selleks saame appi võtta tsükli kõigi sisuraami laste (ingl child) ehk sisuraamis olevate komponentide parameetrite muutmiseks:
for child in sisuraam.winfo_children(): child.grid_configure(padx=5, pady=5)
- Kuidas saaks programmi käivitamisel koheselt aktiveerida tekstisisestuskasti?
Kui programmis on mitmeid tekstisisestuskaste, siis saab ka määrata, millisesse tekstisisestuskasti vaikimisi trükkida saab. Selleks tuleks seada fookus tekstisisestuskastile käsklusega focus(). Näiteks: meetrite_tekstikast.focus()
Nende nippide abil saame eelnevat programmi kohendades alljärgneva programmi:
from tkinter import * # tkinteri põhivahendid from tkinter import ttk # platvormi ühise stiili saamiseks def teisenda(*args): try: a = float(meetrid.get()) kilomeetrid.set(a / 1000) meetrid.set("") except ValueError: kilomeetrid.set("Ei saanud teisendada. Sisesta arv!") meetrid.set("") raam = Tk() raam.title("Meetrite teisendamine") sisuraam = ttk.Frame(raam, padding="3 3 12 12") sisuraam.grid(column=0, row=0, sticky=(N, W, E, S)) raam.columnconfigure(0, weight=1) raam.rowconfigure(0, weight=1) meetrid = StringVar() kilomeetrid = StringVar() meetrite_tekstikast = ttk.Entry(sisuraam, width=7, textvariable=meetrid) meetrite_tekstikast.grid(column=2, row=1, sticky=(W, E)) ttk.Label(sisuraam, textvariable=kilomeetrid).grid(column=2, row=2, sticky=(W, E)) ttk.Button(sisuraam, text="Arvuta!", command=teisenda).grid(column=3, row=3, sticky=W) ttk.Label(sisuraam, text="meetrit").grid(column=3, row=1, sticky=W) ttk.Label(sisuraam, text="on võrdne").grid(column=1, row=2, sticky=E) ttk.Label(sisuraam, text="kilomeetriga.").grid(column=3, row=2, sticky=W) for child in sisuraam.winfo_children(): child.grid_configure(padx=5, pady=5) meetrite_tekstikast.focus() raam.bind('<Return>', teisenda) raam.mainloop()