ttk tkinter multiple frames/windows

10,687

Solution 1

You have to convert the StringVar() to an integer/float or use IntVar() or DoubleVar()

There are other problems as well. Statements like the following return "None" since it is a grid() object and not a Label() object:

self.label1 = ttk.Label(self, text="Enter your weight:").grid(row=0, column=0, sticky=W)   

I think you will also have problems with two Tk() windows open at the same time. Use Toplevel() or separate frames instead.

Solution 2

Thanks Joe, you helped quite a bit and I have stumbled onto the answer... using ttk you can use the notebook, and since both my classes are derived frames, I can just add them to the frames of the notebook...

def main():
#Setup Tk()
window = Tk()

#Setup the notebook (tabs)
notebook = ttk.Notebook(window)
frame1 = ttk.Frame(notebook)
frame2 = ttk.Frame(notebook)
notebook.add(frame1, text="BMI Calc")
notebook.add(frame2, text="Feet to Meters")
notebook.grid()

#Create tab frames
app1 = App1(master=frame1)
app1.grid()
app2 = App2(master=frame2)
app2.grid()

#Main loop
window.mainloop()

That solves the issues :)

Share:
10,687
py_tk_coder
Author by

py_tk_coder

Updated on June 28, 2022

Comments

  • py_tk_coder
    py_tk_coder over 1 year

    The following application I have created is used to demonstrate multiple windows in tkinter. The main problem is that none of the Entry controls, neither in the bmi-calculator or the converter, accept the values in the entry boxes - they get a ValueError when I do a calculation.

    from tkinter import *
    from tkinter import ttk
    from tkinter import messagebox
    
    class App1(ttk.Frame):
        def createWidgets(self):
            #text variables
            self.i_height = StringVar()
            self.i_weight = StringVar()
            self.o_bmi = StringVar()
    
            #labels
            self.label1 = ttk.Label(self, text="Enter your weight:").grid(row=0, column=0, sticky=W)
            self.label2 = ttk.Label(self, text="Enter your height:").grid(row=1, column=0, sticky=W)
            self.label3 = ttk.Label(self, text="Your BMI is:").grid(row=2, column=0, sticky=W)
    
            #text boxes
            self.textbox1 = ttk.Entry(self, textvariable=self.i_weight).grid(row=0, column=1, sticky=E)
            self.textbox2 = ttk.Entry(self, textvariable=self.i_height).grid(row=1, column=1, sticky=E)
            self.textbox3 = ttk.Entry(self, textvariable=self.o_bmi).grid(row=2, column=1, sticky=E)
    
            #buttons
            self.button1 = ttk.Button(self, text="Cancel/Quit", command=self.quit).grid(row=3, column=1, sticky=E)
            self.button1 = ttk.Button(self, text="Ok", command=self.calculateBmi).grid(row=3, column=2, sticky=E)
    
        def calculateBmi(self):
            try:
                self.weight = float(self.i_weight.get())
                self.height = float(self.i_height.get())
                self.bmi = self.weight / self.height ** 2.0
                self.o_bmi.set(self.bmi)
            except ValueError:
                messagebox.showinfo("Error", "You can only use numbers.")
            finally:
                self.i_weight.set("")
                self.i_height.set("")
    
        def __init__(self, master=None):
            ttk.Frame.__init__(self, master)
            self.grid()
            self.createWidgets()
    
    class App2(ttk.Frame):
        def create_widgets(self):
            """Create the widgets for the GUI"""
            #1 textbox (stringvar)
            self.entry= StringVar()
            self.textBox1= ttk.Entry(self, textvariable=self.entry).grid(row=0, column=1)
    
            #5 labels (3 static, 1 stringvar)
            self.displayLabel1 = ttk.Label(self, text="feet").grid(row=0, column=2, sticky=W)
            self.displayLabel2 = ttk.Label(self, text="is equivalent to:").grid(row=1, column=0)
            self.result= StringVar()
            self.displayLabel3 = ttk.Label(self, textvariable=self.result).grid(row=1, column=1)
            self.displayLabel4 = ttk.Label(self, text="meters").grid(row=1, column=2, sticky=W)
    
            #2 buttons
            self.quitButton = ttk.Button(self, text="Quit", command=self.quit).grid(row=2, column=1, sticky=(S,E))
            self.calculateButton = ttk.Button(self, text="Calculate", command=self.convert_feet_to_meters).grid(row=2, column=2, sticky=(S,E))
    
        def convert_feet_to_meters(self):
            """Converts feet to meters, uses string vars and converts them to floats"""
            self.measurement = float(self.entry.get())
            self.meters = self.measurement * 0.3048
            self.result.set(self.meters)
    
        def __init__(self, master=None):
            ttk.Frame.__init__(self, master)
            self.grid()
            self.create_widgets()
    
    def button1_click():
        root = Tk()
        app = App1(master=root)
        app.mainloop()
    
    def button2_click():
        root = Tk()
        app = App2(master=root)
        app.mainloop()
    
    def main():
        window = Tk()
        button1 = ttk.Button(window, text="bmi calc", command=button1_click).grid(row=0, column=1)
        button2 = ttk.Button(window, text="feet conv", command=button2_click).grid(row=1, column=1)
        window.mainloop()
    
    if __name__ == '__main__':
        main()
    

    How can I fix this, but still maintaining the class structure and the use of python3? BTW - Anything similar to C#'s form1.Show()?

  • Russell Smith
    Russell Smith over 12 years
    grid isn't an object, nor does it return an object. It's just a function. But you are correct that Label(...).grid(...) doesn't return anything useful.
  • py_tk_coder
    py_tk_coder over 12 years
    Its only for the layout, it is in the function create_widgets that sets up the widgets in the frames. I use it a class as it is helpful to setup all the widgets in one place, and I like single liners :)
  • Russell Smith
    Russell Smith over 12 years
    @py_tk_coder: if that is the case, do not assign the result to instance variables. It's pointles, confusing, and makes your "single liners" longer than necessary.