Harrison Betts
Harrison Betts

Reputation: 15

Python Tkinter open multiple windows within a function

I have an inbuilt calculator within my program. My main program was designed to be somewhat similar to Microsoft Bob. Now when the user presses the 'Calculator' Button in the main focus, it opens up the part of the calculator where you define your 2 numbers and the operator. When you press 'Results' the answer does not appear in any shape of form until my main program is closed. Any help? Attached is the calculator code sample, and more than happy to change the second window to something else. BTW this is for a school project.

def Calculator():
        calculator = Tk()
        Number1 = DoubleVar()
        Number2 = DoubleVar()
        Operator = IntVar()
        Operator.set(1)
        Entry(calculator,textvariable=Number1,justify="c").grid()
        Entry(calculator,textvariable=Number2,justify="c").grid()
        Radiobutton(calculator,text="Add",variable=Operator,value=1).grid()
        Radiobutton(calculator,text="Subtract",variable=Operator,value=2).grid()
        Radiobutton(calculator,text="Multiply",variable=Operator,value=3).grid()
        Radiobutton(calculator,text="Divide",variable=Operator,value=4).grid()
        Radiobutton(calculator,text="Square",variable=Operator,value=5).grid()
        Radiobutton(calculator,text="Square root",variable=Operator,value=6).grid()
        Button(calculator,text="results",command=calculator.destroy,width=16).grid()
        Number1=Number1.get()
        Number2=Number2.get()
        Operator=Operator.get()
        if Operator==1:Results=Number1+Number2
        if Operator==2:Results=Number1-Number2
        if Operator==3:Results=Number1*Number2
        if Operator==4:Results=Number1/Number2
        if Operator==5:Results=math.pow(Number1,Number2)
        if Operator==6:Results=Number1*(1/Number2)
        Results = "The answer is "+str(Results)
        Answer = Tk()
        Answer.geometry("150x150")
        Label(Answer, text=Results).place(relx=.5,rely=.5,anchor="center")
        Answer.mainloop()

Upvotes: 0

Views: 561

Answers (1)

abarnert
abarnert

Reputation: 365717

You can't have multiple Tk objects with their own mainloops.

Or, rather, you can, but whichever one is currently running mainloop, none of the others (and none of their children) gets to do anything until that mainloop finishes.

What you want is to have multiple Toplevel widgets, with the same Tk as their master. (If you just have one Tk, as you usually do, you can leave that as the default.)


But you have another, equally serious problem here.

You're creating a Calculator with a bunch of Tk vars attached, then immediately trying to read those vars and do something with them. You can't do that.

What you need to do is to put all of that in the callback to some kind of user event, like clicking the Results button.


You have one more problem in your code that makes things a bit harder:

Number1=Number1.get()

What you really want here is two separate variables, one the Tk var, and the other an int. And then you need to make the Tk var accessible in the results callback in some way. The obvious way is to move all of this to a class, and store all your Tk vars as instance attributes. If you don't know how to do that, you can always use globals. (Not ideal, but until you learn classes, it's fine.) Then the actual numbers are just local to the callback function.


Putting it all together:

def Calculator(root):
    global Number1, Number2, Operator
    calculator = Toplevel()
    Number1 = DoubleVar()
    Number2 = DoubleVar()
    Operator = IntVar()
    Operator.set(1)
    Entry(calculator,textvariable=Number1,justify="c").grid()
    Entry(calculator,textvariable=Number2,justify="c").grid()
    Radiobutton(calculator,text="Add",variable=Operator,value=1).grid()
    Radiobutton(calculator,text="Subtract",variable=Operator,value=2).grid()
    Radiobutton(calculator,text="Multiply",variable=Operator,value=3).grid()
    Radiobutton(calculator,text="Divide",variable=Operator,value=4).grid()
    Radiobutton(calculator,text="Square",variable=Operator,value=5).grid()
    Radiobutton(calculator,text="Square root",variable=Operator,value=6).grid()
    Button(calculator,text="results", command=lambda event: calculate(calculator), width=16).grid()

def calculate(calculator):
    n1=Number1.get()
    n2=Number2.get()
    op=Operator.get()
    if op==1:Results=n1+n2
    if op==2:Results=n1-n2
    if op==3:Results=n1*n2
    if op==4:Results=n1/n2
    if op==5:Results=math.pow(n1,n2)
    if op==6:Results=n1*(1/n2)
    Results = "The answer is "+str(Results)
    calculator.destroy()

    Answer = Toplevel()
    Answer.geometry("150x150")
    Label(Answer, text=Results).place(relx=.5,rely=.5,anchor="center")

root = Tk()
# Presumably your real code has some top-level stuff, where the
# user can ask you to open a calculator, like a button whose
# command calls the Calculator function? But here, we'll just:
Calculator(root)
root.mainloop()

Upvotes: 2

Related Questions