Ako vytvoriť grafické rozhranie kalkulačky pomocou Tkinter: 8 krokov

Vytvorenie textovej kalkulačky je bežným cvičením pre začiatočníkov. Keď však už máte stredne pokročilé znalosti programovania, možno budete chcieť, aby vaša kalkulačka mala grafické rozhranie, ako to má väčšina softvéru. Tento článok ukazuje, ako napísať kalkulačku, ktorá má grafické rozhranie, pomocou knižnice Tkinter v jazyku Python 3.

Kroky

Otvorte textový editor alebo IDE. Ak nepreferujete konkrétny program, najjednoduchšie je použiť IDLE, IDE, ktoré sa zvyčajne inštaluje spolu s Pythonom.

Import Tkinter. Zvyčajne sa inštaluje spolu s Pythonom, takže nemusíte inštalovať nič nové. Na začiatok svojho programu napíšte nasledujúci riadok:

from tkinter import *
from tkinter import messagebox # musí sa importovať samostatne

Uložte a spustite program, aby ste otestovali, či je Tkinter správne nainštalovaný. Ak to funguje, neuvidíte nič, program len importuje Tkinter a ukončí sa. Ak to nefunguje (i. e. sa objaví nejaké chybové hlásenie), ďalšie kroky tiež nebudú fungovať, kým problém neodstránite.

Definujte a Okno podtrieda Rámček trieda. Táto podtrieda bude definovať, ako bude vyzerať okno kalkulačky. Zatiaľ len uveďte základný kód, ktorý inicializuje okno:

Trieda Window(Frame):
def __init__(self, master=None):
Rám.__init__(self, master)
self.master = master

Zabezpečte, aby sa okno zobrazilo. Už ste definovali, ako okno vyzerá, ale musíte ho aj skutočne vytvoriť.

  • Vyvolať Tk() funkcia na inicializáciu Tkintera a a vrátenie objektu, ktorý vám umožní ovládať hlavné okno.
  • Vytvorte okno Okno trieda, ktorá je pripojená k tomuto objektu.
  • Nastavenie nadpisu pre okno.
  • Zobraziť okno a reagovať na udalosti.
root = Tk()
app = Window(root)
root.wm_title("Kalkulačka")
root.mainloop()

Pridanie textového poľa. Tu sa zobrazí výpočet a jeho výsledok. Prvá funkcia v nasledujúcom kóde vytvorí textové okno, ktoré má biele pozadie, čierny text a je vysoké 1 riadok. Druhá funkcia skutočne vloží text, ktorý je „0“. Tento kód patrí do __init__() funkcia Okno Trieda.

# Vytvorenie textového poľa výsledku
self.resultField = Text(master, bg="#FFFFFF", fg="#000000", height=1)
self.resultField.insert(INSERT, "0")

Umiestnite textové pole do mriežky. Mriežka umiestni vaše widgety, ako napríklad textové pole a tlačidlá. Keďže mriežka by mala byť na vrchu, umiestnite ju do riadku 0. Keďže je to cez celý riadok, ktorý bude široký 4 stĺpce, nie je potrebné uvádzať číslo stĺpca, ale je potrebné uviesť, že sa rozprestiera cez 4 stĺpce.

                self.resultField.grid(row=0, columnspan=4)

Vytvorenie a zarovnanie číselných a operačných tlačidiel. Funkcia spätného volania pre každé tlačidlo bude self.notice s tým, čo je napísané na tlačidle ako argument. Keďže funkcie s argumentmi nemôžete použiť priamo ako funkciu spätného volania, budete ju musieť vložiť do inštrukcie lambda. Túto funkciu zatiaľ definujte na pass (nerobiť nič) alebo vypísať túto hodnotu.

# Vytvorenie tlačidiel čísla a operácie
b1 = Button(master, text="1", command=lambda: self.notice(1))
b2 = Button(master, text="2", command=lambda: self.notice(2))
b3 = Button(master, text="3", command=lambda: self.notice(3))
bPlus = Button(master, text="+", command=lambda: self.notice("+"))
b4 = Button(master, text="4", command=lambda: self.notice(4))
b5 = Button(master, text="5", command=lambda: self.notice(5))
b6 = Button(master, text="6", command=lambda: self.notice(6))
bMinus = Button(master, text="-", command=lambda: self.notice("-"))
b7 = Button(master, text="7", command=lambda: self.notice(7))
b8 = Button(master, text="8", command=lambda: self.notice(8))
b9 = Button(master, text="9", command=lambda: self.notice(9))
bMultip = Button(master, text="*", command=lambda: self.notice("*"))
b0 = Button(master, text="0", command=lambda: self.notice(0))
bLeft = Button(master, text="(", command=lambda: self.notice("("))
bRight = Button(master, text=")", command=lambda: self.notice(")"))
bDivide = Button(master, text="/", command=lambda: self.notice("/"))
# Zarovnanie tlačidiel čísla a operácie
b1.grid(riadok=1, stĺpec=0)
b2.grid(row=1, column=1)
b3.grid(riadok=1, stĺpec=2)
bPlus.grid(row=1, column=3)
b4.grid(row=2, column=0)
b5.grid(row=2, column=1)
b6.grid(row=2, column=2)
bMinus.grid(row=2, column=3)
b7.grid(row=3, column=0)
b8.grid(row=3, column=1)
b9.grid(riadok=3, stĺpec=2)
bMultip.grid(row=3, column=3)
b0.grid(row=4, column=0)
bLeft.grid(riadok=4, stĺpec=1)
bRight.grid(row=4, column=2)
bDeliť.grid(row=4, column=3)
def notice(self, num):
print(num)

Uložiť a spustiť súbor, aby sa otestovalo, či sú tlačidlá správne zarovnané. Ak nie, upravte pozíciu. Hoci tlačidlá, okno a pole môžu v rôznych systémoch vyzerať rôzne, približne by to malo vyzerať takto:

Zapíšte self.upozornenie funkcia. Už ste to definovali tak, že zobrazenie tlačidla funguje, ale kód ešte nerobí to, čo má. Namiesto vypísania hodnoty by sa mala zobraziť v poli výsledku, aby sa používateľovi ukázalo, že kalkulačka si všimla jeho vstup. Zvyčajne môže program len doplniť hodnotu, ale ak je v poli výpočtu prítomné len číslo 0, táto 0 by sa mala odstrániť a nahradiť hodnotou.

  • „0.0“, ktorá sa nachádza v get() a delete() funkcie označujú začiatok textu textového poľa. Je vo formáte „lineNumber.columnNumber“, ktorý sa používa na indexovanie textu textového poľa.
        def notice(self, num):
if self.resultField.get("0.0", END) == "0\n":
self.resultField.delete("0.0", END)
self.resultField.insert(INSERT, str(num))

Pridať tlačidlá na výpočet a vymazanie. Momentálne je možné zadávať len čísla a operácie. Ale kalkulačka by mala skutočne vypočítať výsledok toho, čo zadá používateľ. Po dokončení tohto výpočtu by malo byť možné vymazať výstup a vypočítať niečo iné. Na vykonanie týchto vecí pridajte ďalšie dve tlačidlá v riadku 5. Ak ich chcete vizuálne odlíšiť od ostatných, urobte ich tak, aby sa rozprestierali cez 2 stĺpce. Nastavte self.displayRes a self.vymazať ako funkcie spätného volania.

# Vytvorenie a zarovnanie tlačidiel výpočtu
bCalculate = Button(master, text="=", command=self.displayRes)
bClear = Button(master, text="Clear", command=self.clear)
bVypočítať.grid(row=5, column=0, columnspan=2)
bClear.grid(row=5, column=2, columnspan=2)

Definujte clear() funkcia. Mala by vymazať všetok text v textovom poli a nahradiť ho číslom 0.

def clear(self):
self.resultField.delete("0.0", KONIEC)
self.resultField.insert(INSERT, "0")

Definujte funkciu na zobrazenie výsledku výpočtu. Skutočná funkcia výpočtu bude pomerne zložitá a bola by ešte zložitejšia, keby mala získať aj vstup z textového poľa a zapísať do neho výstup. Preto by ste mali na tento účel definovať ďalšiu funkciu.

        def displayRes(self):
res = self.vypočítať(self.resultField.get("0.0",END)[:-1])
self.resultField.delete("0.0", END)
self.resultField.insert(INSERT, str(res))

Definujte výpočtovú funkciu. Toto je najzložitejšia funkcia celého programu. Make it rekurzívne, i. e. volanie seba samého s inými argumentmi. To umožňuje redukovať výraz na jednoduchšie výrazy, až kým nie je len číslom, potom vykonať zadanú operáciu s číslom a druhým číslom, potom použiť tento výsledok v nie príliš jednoduchom výraze atď.

  • Nepokračovať, ak je vstup „ERROR“. Tento reťazec sa použije na označenie, že výpočet zlyhal. Keďže pri neúspešnom výsledku nie je možné pokračovať vo výpočte, funkcia by mala sama vrátiť len „ERROR“.
            def calculate(self, task):
    if task == "ERROR":
    return "ERROR" # nepokračovať, ak sa v základnom volaní vyskytla chyba
    
  • Kontrola, či je vstupné číslo jedno číslo. Ak je, vráťte toto číslo, pretože už nie je čo počítať. Všimnite si, že nasledujúci výraz vyvolá ValueError ak vstupom nie je jedno číslo. Skutočný výpočet a rekurzia sa uskutoční, keď sa vyskytne takáto chyba.
                    v prípade tesk: try:
    return(float(task))
    okrem ValueError:
    
  • Overiť, či existujú zátvorky. Ak áno, vypočítajte výsledok výrazu vnútri zátvoriek oddelene od ostatných vecí. Ak nie, pokračujte v kontrole ďalších operácií.
                            if ")" in task:
    level = 0
    maxLevelStartIndex = 0
    maxLevelEndIndex = 0
    for i in range(0, len(task)):
    if task[i] == "(":
    level += 1
    maxLevelStartIndex = i
    if task[i] == ")":
    level -= 1
    if level != 0:
    print("ERROR: zátvorky sa nezhodujú: %i vrstvy príliš veľa vo výraze %s" %(level, task))
    return "ERROR"
    for i in range(maxLevelStartIndex, len(task)):
    if task[i] == ")":
    maxLevelEndIndex = i
    break
    newTask = task[:maxLevelStartIndex] + str(self.calculate(task[maxLevelStartIndex+1:maxLevelEndIndex]) + task[maxLevelEndIndex+1:]
    return self.calculate(newTask)
    
  • Ostatné operácie (sčítanie, odčítanie, násobenie, delenie) sú usporiadané podľa priority. Program najprv rozdelí podľa + alebo – a vypočíta dve časti, až potom podľa * alebo / . Všimnite si, že sa zachytí chyba, ktorá nastane, keď sa pokúsite deliť 0, a vráti „ERROR“, ak sa tak stane. Ak sa chyba nevyskytne, vráti výsledok.
                            elif "+" v task:
    tesk = task.split("+")
    res = self.calculate(tesk[0])
    for t in tesk[1:]:
    res += self.vypočítať(t)
    return res
    elif "-" v task:
    tesk = task.split("-")
    res = self.calculate(tesk[0])
    for t in tesk[1:]:
    res -= self.calculate(t)
    return res
    elif "*" v task:
    tesk = task.split("*")
    res = self.calculate(tesk[0])
    for t in tesk[1:]:
    res *= self.calculate(t)
    return res
    elif "/" v task:
    tesk = task.split("/")
    res = self.calculate(tesk[0])
    for t in tesk[1:]:
    try:
    res /= self.calculate(t)
    except ZeroDivisionError:
    print("ERROR: delenie 0")
    return "ERROR"
    return res
    
  • Ak sa vstup nepodarilo previesť na číslo nie preto, že ide o výraz, ale z iného dôvodu, vráti to chybu. Je to potrebné, pretože textové pole Tkinter umožňuje používateľovi zadávať vstup na klávesnici. Ak používateľ zadá písmeno, malo by to vrátiť chybu a tento kód to zabezpečí.
                                    print("ERROR: invalid expression")
    return "ERROR"
    

Vytvorte grafické chybové hlásenia. Práve teraz, ak dôjde k chybe, zobrazí sa „ERROR“ v textovom poli výsledku a vypíše sa chyba do terminálu alebo IDE, z ktorého ste spustili Python. Dobré grafické rozhranie by však malo chyby zobrazovať aj graficky. Toto sa vykonáva pomocou messagebox.showerror funkcia. Ako prvý argument sa berie nadpis správy a ako druhý text správy. Môžete použiť „Error“ ako nadpis správy a správu, ktorá bola predtým vypísaná ako správa. Napríklad nahradiť

print("ERROR: delenie 0")

s

messagebox.showerror("Chyba", "ERROR: delenie 0")

Skontrolujte svoj kód. Celý váš kód by mal teraz vyzerať takto.

from tkinter import *
from tkinter import messagebox
trieda Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
# Vytvorenie textového poľa výsledku
self.resultField = Text(master, bg="#FFFFFF", fg="#000000", height=1, width=20)
self.resultField.insert(INSERT, "0")
self.resultField.grid(row=0, columnspan=4)
# Vytvorenie tlačidiel s číslami a operáciami
b1 = Button(master, text="1", command=lambda: self.notice(1))
b2 = Button(master, text="2", command=lambda: self.notice(2))
b3 = Button(master, text="3", command=lambda: self.notice(3))
bPlus = Button(master, text="+", command=lambda: self.notice("+"))
b4 = Button(master, text="4", command=lambda: self.notice(4))
b5 = Button(master, text="5", command=lambda: self.notice(5))
b6 = Button(master, text="6", command=lambda: self.notice(6))
bMinus = Button(master, text="-", command=lambda: self.notice("-"))
b7 = Button(master, text="7", command=lambda: self.notice(7))
b8 = Button(master, text="8", command=lambda: self.notice(8))
b9 = Button(master, text="9", command=lambda: self.notice(9))
bMultip = Button(master, text="*", command=lambda: self.notice("*"))
b0 = Button(master, text="0", command=lambda: self.notice(0))
bLeft = Button(master, text="(", command=lambda: self.notice("("))
bRight = Button(master, text=")", command=lambda: self.notice(")"))
bDivide = Button(master, text="/", command=lambda: self.notice("/"))
# Zarovnanie tlačidiel čísla a operácie
b1.grid(row=1, column=0)
b2.grid(row=1, column=1)
b3.grid(row=1, column=2)
bPlus.grid(row=1, column=3)
b4.grid(row=2, column=0)
b5.grid(row=2, column=1)
b6.grid(row=2, column=2)
bMinus.grid(row=2, column=3)
b7.grid(row=3, column=0)
b8.grid(row=3, column=1)
b9.grid(row=3, column=2)
bMultip.grid(row=3, column=3)
b0.grid(row=4, column=0)
bLeft.grid(row=4, column=1)
bRight.grid(row=4, column=2)
bDivide.grid(row=4, column=3)
# Vytvorenie a zarovnanie tlačidiel výpočtu
bCalculate = Button(master, text="=", command=self.displayRes)
bClear = Button(master, text="Clear", command=self.clear)
bCalculate.grid(row=5, column=0, columnspan=2)
bClear.grid(row=5, column=2, columnspan=2)
def notice(self, num):
if self.resultField.get("0.0", END) == "0\n":
self.resultField.delete("0.0", END)
self.resultField.insert(INSERT, str(num))
def clear(self):
self.resultField.delete("0.0", END)
self.resultField.insert(INSERT, "0")
def displayRes(self):
res = self.vypočítať(self.resultField.get("0.0",END)[:-1])
self.resultField.delete("0.0", END)
self.resultField.insert(INSERT, str(res))
def vypočítať(self, task):
if task == "ERROR":
return "ERROR" # nepokračujte, ak došlo k chybe v základnom volaní
try:
return(float(task))
okrem ValueError:
if ")" in task:
level = 0
maxLevelStartIndex = 0
maxLevelEndIndex = 0
for i in range(0, len(task)):
if task[i] == "(":
level += 1
maxLevelStartIndex = i
ak task[i] == ")":
level -= 1
if level != 0:
messagebox.showerror("Chyba", "ERROR: zátvorky sa nezhodujú: %i vrstvy príliš veľa vo výraze %s" %(level, task))
return "ERROR"
for i in range(maxLevelStartIndex, len(task)):
if task[i] == ")":
maxLevelEndIndex = i
break
newTask = task[:maxLevelStartIndex] + str(self.calculate(task[maxLevelStartIndex+1:maxLevelEndIndex])) + task[maxLevelEndIndex+1:]
return self.calculate(newTask)
elif "+" v task:
tesk = task.split("+")
res = self.calculate(tesk[0])
for t in tesk[1:]:
res += self.vypočítať(t)
return res
elif "-" in task:
tesk = task.split("-")
res = self.calculate(tesk[0])
for t in tesk[1:]:
res -= self.vypočítať(t)
return res
elif "*" v task:
tesk = task.split("*")
res = self.calculate(tesk[0])
for t in tesk[1:]:
res *= self.vypočítať(t)
return res
elif "/" v task:
tesk = task.split("/")
res = self.calculate(tesk[0])
for t in tesk[1:]:
try:
res /= self.calculate(t)
except ZeroDivisionError:
messagebox.showerror("Error", "ERROR: delenie 0")
return "ERROR"
return res
inak:
messagebox.showerror("Chyba", "ERROR: neplatný výraz")
return "ERROR"
root = Tk()
app = Window(root)
root.wm_title("Kalkulačka")
root.mainloop()

Toto je celkom 120 riadkov a 116 riadkov bez započítania komentárov.

  • Uložte a spustite kód. Hotovo. Teraz si to vyskúšajte a/alebo sa tešte z vlastnej kalkulačky. Malo by to vyzerať približne ako na tomto obrázku: