Search code examples
pythonpython-3.xuser-interfacetkintertkinter-entry

Python Tkinter Entry not placing


In Croatia we have competitions where you make apps. I'm making an app to help 1st and 2nd graders learn and revise math. I just started recently so it doesn't have almost anything. The problem is that when variable: mode = "number" , entries aren't placed. Btw when opening the app you will be presented with 4 options. They are addition, subtraction, multiplication and division. I translated it from Croatian to English so you can understand. When you run the program press the Addition button. Then you will see the task but entries missing. If you change the value of the variable mode to mode = "result", entries are placed. I tried everything but couldn't get it to work.

Here's the code:

import tkinter as tk
import random

wn = tk.Tk()
wn.config(width = 550, height = 500)
wn.resizable(False, False)
wn.title("Learn and Revise")

number1_1 = 0
number1_2 = 0
number2_1 = 0
number2_2 = 0
number3_1 = 0
number3_2 = 0
number4_1 = 0
number4_2 = 0
number5_1 = 0
number5_2 = 0

def makeRandomNumbers():

    global number1_1, number1_2
    global number2_1, number2_2
    global number3_1, number3_2
    global number4_1, number4_2
    global number5_1, number5_2

    if mode == "number":
        while True:
            number1_1 = random.randint(0, 10)
            number1_2 = random.randint(0, 10)
            if number1_1 > number1_2:
                pass
            else:
                break
        while True:
            number2_1 = random.randint(0, 10)
            number2_2 = random.randint(0, 10)
            if number2_1 > number2_2:
                pass
            else:
                break
        while True:
            number3_1 = random.randint(0, 10)
            number3_2 = random.randint(0, 10)
            if number3_1 > number3_2:
                pass
            else:
                break
        while True:
            number4_1 = random.randint(0, 10)
            number4_2 = random.randint(0, 10)
            if number4_1 > number4_2:
                pass
            else:
                break
        while True:
            number5_1 = random.randint(0, 10)
            number5_2 = random.randint(0, 10)
            if number5_1 > number5_2:
                pass
            else:
                break
    elif mode == "result":
        number1_1 = random.randint(0, 10)
        number1_2 = random.randint(0, 10)
        number2_1 = random.randint(0, 10)
        number2_2 = random.randint(0, 10)
        number3_1 = random.randint(0, 10)
        number3_2 = random.randint(0, 10)
        number4_1 = random.randint(0, 10)
        number4_2 = random.randint(0, 10)
        number5_1 = random.randint(0, 10)
        number6_2 = random.randint(0, 10)

def placeTasks(oper):

    global operation
    operation = oper

    makeTasks()

    wipeMenu()

    button_check.place(x = 310, y = 225)
    label1.place(x = 150, y = 125)
    label2.place(x = 150, y = 175)
    label3.place(x = 150, y = 225)
    label4.place(x = 150, y = 275)
    label5.place(x = 150, y = 325)

    if mode == "number":
        entry1.place(x = 240, y = 130)
        entry2.place(x = 240, y = 180)
        entry3.place(x = 240, y = 230)
        entry4.place(x = 240, y = 280)
        entry5.place(x = 240, y = 330)

    elif mode == "result":
        entry1.place(x = 240, y = 130)
        entry2.place(x = 240, y = 180)
        entry3.place(x = 240, y = 230)
        entry4.place(x = 240, y = 280)
        entry5.place(x = 240, y = 330)

task1 = 0
task2 = 0
task3 = 0
task4 = 0
task5 = 0

def makeTasks():

    global task1, task2, task3, task4, task5
    global label1, label2, label3, label4, label5

    makeRandomNumbers()

    operation_sign = ""
    if operation == "addition":
        operation_sign = '+'
    elif operation == "subtraction":
        operation_sign = '-'
    elif operation == "multiplication":
        operation_sign = '•'
    elif operation == "division":
        operation_sign = '÷'

    if mode == "result":
        task1 = "{} {} {} =".format(number1_1, operation_sign, number1_2)
        task2 = "{} {} {} =".format(number2_1, operation_sign, number2_2)
        task3 = "{} {} {} =".format(number3_1, operation_sign, number3_2)
        task4 = "{} {} {} =".format(number4_1, operation_sign, number4_2)
        task5 = "{} {} {} =".format(number5_1, operation_sign, number5_2)
    elif mode == "number":
        task1 = "{} {}            = {}".format(number1_1, operation_sign, number1_2)
        task2 = "{} {}            = {}".format(number2_1, operation_sign, number2_2)
        task3 = "{} {}            = {}".format(number3_1, operation_sign, number3_2)
        task4 = "{} {}            = {}".format(number4_1, operation_sign, number4_2)
        task5 = "{} {}            = {}".format(number5_1, operation_sign, number5_2)

    label1 = tk.Label(wn, text = task1, font = ("Arial", 15))
    label2 = tk.Label(wn, text = task2, font = ("Arial", 15))
    label3 = tk.Label(wn, text = task3, font = ("Arial", 15))
    label4 = tk.Label(wn, text = task4, font = ("Arial", 15))
    label5 = tk.Label(wn, text = task5, font = ("Arial", 15))

operation = ""
mode = "number"

button_check = tk.Button(wn, width = 20, text = "Check")

label1 = tk.Label(wn, text = task1, font = ("Arial", 15))
entry1 = tk.Entry(wn, width = 7)

label2 = tk.Label(wn, text = task2, font = ("Arial", 15))
entry2 = tk.Entry(wn, width = 7)

label3 = tk.Label(wn, text = task3, font = ("Arial", 15))
entry3 = tk.Entry(wn, width = 7)

label4 = tk.Label(wn, text = task4, font = ("Arial", 15))
entry4 = tk.Entry(wn, width = 7)

label5 = tk.Label(wn, text = task5, font = ("Arial", 15))
entry5 = tk.Entry(wn, width = 7)


def placeMenu():

    menu_label1.place(x = 175, y = 75)
    button1.place(x = 200, y = 150)
    button2.place(x = 200, y = 200)
    button3.place(x = 200, y = 250)
    button4.place(x = 200, y = 300)

def wipeMenu():

    menu_label1.destroy()
    button1.destroy()
    button2.destroy()
    button3.destroy()
    button4.destroy()

menu_label1 = tk.Label(wn, text = "Revise", font = ("Arial", 35))

button1 = tk.Button(wn, width = 20, text = "Addition", command = lambda: placeTasks("addition"))

button2 = tk.Button(wn, width = 20, text = "Subtraction")

button3 = tk.Button(wn, width = 20, text = "Multiplication")

button4 = tk.Button(wn, width = 20, text = "Division")

placeMenu()

wn.mainloop()

Solution

  • TL;DR

    Postavi font prilikom inicijalizacije entrya, preimenuj if statement i ukloni globalnu varijablu te koristi lokalnu (oper)


    Prvo što vidim je mnoštvo ponavljanja. Napravi funkciju s više parametara na kojima ćeš izvršavati for loopove - kod će biti kraći i čitljiviji 20 puta. Tkinter je jednostavan, ali nije praktičan ukoliko nije objektno orijentiran (preporučujem tk.Toplevel klase za prebacivanje prozora, onda samo switchaš screenove i nema potrebe za brisanjem i postavljanjem, što dodatno ubrzava izvrašavanje). Idealno bi bilo kreirati class za svaku aritmetičku operaciju i uz to ne koristiti (spore) lambda anonimne funkcije samo za pozivanje s atributima. Dakle, kod bi izgledao otprilike ovako:

    for (akcija, klasa) in zip(["Addition", "Substraction", ...], lista_klasi):
    
        button = tk.Button(wn, width=20, text=akcija, command=klasa);
        ...
        button.pack()  # Izbjegavaj .place(), uvijek samo pack() ili grid()
        ...
    
    class Solution(tk.Toplevel):
        def __init__(self, atributi):
            super().__init__()
            self.attributes("-topmost", False)
            self.solution = tk.Canvas(self, bg="white" ...)
            self.solution.pack()
            ...
            # Za najbolji izgled postavljaj widgete na canvas...
            self.solution.create_window(w, h, window=atribut[neki])
    
            # Također, ako želiš ostati u istom prozoru, spremi widgete i koristi:
            self.canvas.delete("all")
    

    Osobno koristim pack jer je najjednostavniji, u početku nezgodan jer ne dobivaš izgledom točno kako zamišljaš ali kad pohvataš sve ne bi se nikad vratio na place(), osim ako nije nužno :)


    Zasad prvo prouči sve pojašnjene primjere ovdje. Tek kad savladaš tkinter kreni na kivy ako misliš stvarno rasturit na natjecanju.