I'm studying GUI for Python, and I don't know how to disable a button with a check button. Which trigger does Python use to verify if I mark the check button? Follow some code I wrote trying to do it, but without success.
Sorry for my bad English.
from tkinter import *
from tkinter import ttk
class HelloApp:
def __init__(self, master):
self.label = ttk.Label(master, text="Hello, Tkinter!")
self.button1 = ttk.Button(master, text="Texas", command=self.texas_hello)
self.button2 = ttk.Button(master, text="Hawaii", command=self.hawaii_hello)
value_check = IntVar()
def disable_button(button):
button.config(state=DISABLED)
def enable_button(button):
button.config(state=NORMAL)
checkbutton = ttk.Checkbutton(master, variable=value_check, text='Deactivate!',
onvalue=enable_button(self.button1),
offvalue=disable_button(self.button1))
self.label.grid(row=0, column=0, columnspan=2)
self.button1.grid(row=1, column=0)
self.button2.grid(row=1, column=1)
checkbutton.grid(row=1, column=2)
print(value_check)
def texas_hello(self):
self.label.config(text='Howdy, Tkinter!')
def hawaii_hello(self):
self.label.config(text='Aloha, Tkinter!')
def main():
root = Tk()
HelloApp(root)
root.mainloop()
if __name__ == "main": main()
main()
You have to pass a function to command, this function is the one that will be notified every time there is a change, and you can get the status through value_check.
...
value_check = IntVar()
def disable_enable_button(button):
self.button1.config(state=DISABLED if value_check.get() else NORMAL)
checkbutton = ttk.Checkbutton(master, variable=value_check, text='Deactivate!',
command=disable_enable_button)
....
use command option. you can set the default status using value_check.set(1/0).
def disable_button(self, button):
print('disable button')
button.config(state=DISABLED)
def enable_button(self, button):
print('enable button')
button.config(state=NORMAL)
def changebutton(self):
print('changebutton=', self.value_check.get())
if self.value_check.get()==1:
self.enable_button(self.button1)
else:
self.disable_button(self.button1)
def __init__(self, master):
self.label = ttk.Label(master, text="Hello, Tkinter!")
self.button1 = ttk.Button(master, text="Texas", command=self.texas_hello)
self.button2 = ttk.Button(master, text="Hawaii", command=self.hawaii_hello)
self.value_check = IntVar()
self.checkbutton = ttk.Checkbutton(master, variable=self.value_check, text='Activate!',
onvalue=1, offvalue=0,
command=self.changebutton)
self.value_check.set(0)
self.changebutton()
self.label.grid(row=0, column=0, columnspan=2)
self.button1.grid(row=1, column=0)
self.button2.grid(row=1, column=1)
self.checkbutton.grid(row=1, column=2)
print(self.value_check.get())
Follows the code including some radio buttons to play with the checkbox.
class HelloApp:
def __init__(self, master):
self.label = ttk.Label(master, text="Hello, Tkinter!")
self.button1 = ttk.Button(master, text="Texas", command=self.texas_hello)
self.button2 = ttk.Button(master, text="Hawaii", command=self.hawaii_hello)
self.value_check = IntVar()
self.value_check.set(0)
self.checkbutton = ttk.Checkbutton(master, variable=self.value_check, text='Activate!',
onvalue=1, offvalue=0,
command=self.disable_enable_button)
self.choice = StringVar()
self.frame_radio = ttk.Frame(master).grid(row=3, column=3)
self.radiobutton1 = ttk.Radiobutton(self.frame_radio, text='Button 1', variable=self.choice, value='button1')
self.radiobutton1.grid(row=2, column=2)
self.radiobutton2 = ttk.Radiobutton(self.frame_radio, text='Button 2', variable=self.choice, value='button2')
self.radiobutton2.grid(row=3, column=2)
self.label.grid(row=0, column=0, columnspan=2)
self.button1.grid(row=1, column=0)
self.button2.grid(row=1, column=1)
self.checkbutton.grid(row=1, column=2)
def texas_hello(self):
self.label.config(text='Howdy, Tkinter!')
def hawaii_hello(self):
self.label.config(text='Aloha, Tkinter!')
def disable_enable_button(self):
self.button1.config(
state=DISABLED if self.value_check.get() and self.choice.get() == 'button1' else NORMAL)
self.button2.config(
state=DISABLED if self.value_check.get() and self.choice.get() == 'button2' else NORMAL)
def main():
root = Tk()
HelloApp(root)
root.mainloop()
Related
I have a small test application using Python tkinter that I got to work. The problem is that it does not exit properly when the "Quit" button is pressed. It is a two-frame tabbed application where I started with the StackOverflow question ttk tkinter multiple frames/windows.
It is now a full example that works, but needs work because it doesn't quit and exit properly. When I press the "Quit" button, it kills the frame for that tab, but the application doesn't quit and exit properly. I have to hit the Window "X" Close icon to close it.
My main question is how (and where?) do I test for the event on either the "Quit" button on the "Feet to Meters" calculator, or the "Cancel/Quit" button on the BMI calculator.
A second question I have is that the design of the application seems inefficient to me, because it creates two widgets "Frame" objects, each with their own set of buttons, including 2 "quit" buttons. How do I put these tabs and frames into a parent window and then add a quit button on that parent window to close the entire application.
I modified the buttons to properly destroy the Frame that the button is in:
Changed button2 "command=self.quit" to "command=self.destroy"
self.button2 = ttk.Button(self, text="Cancel/Quit", command=self.quit).grid(row=3, column=1, sticky=E)
to
self.button2 = ttk.Button(self, text="Cancel/Quit", command=self.destroy).grid(row=3, column=1, sticky=E)
""" Created on Thu Jul 11 17:20:22 2019 """
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
class App1(ttk.Frame):
""" This application calculates BMI and returns a value. """
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.createWidgets()
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="Ok", command=self.calculateBmi).grid(row=3, column=2, sticky=E)
## Changed button2 "command=self.quit" to "command=self.destroy"
# self.button2 = ttk.Button(self, text="Cancel/Quit", command=self.quit).grid(row=3, column=1, sticky=E)
self.button2 = ttk.Button(self, text="Cancel/Quit", command=self.destroy).grid(row=3, column=1, sticky=E)
#exitApplication = tk.Button(root, text='Exit Application', command=root.destroy)
#canvas1.create_window(85, 300, window=exitApplication)
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("")
class App2(ttk.Frame):
""" Application to convert feet to meters or vice versa. """
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
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.calculateButton = ttk.Button(self, text="Calculate", command=self.convert_feet_to_meters).grid(row=2, column=2, sticky=(S,E))
self.quitButton = ttk.Button(self, text="Quit", command=self.destroy).grid(row=2, column=1, sticky=(S,E))
#exitApplication = tk.Button(root, text='Exit Application', command=root.destroy)
#canvas1.create_window(85, 300, window=exitApplication)
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)
### CODE BELOW COMMENTED OUT WHEN JOINING ORIGINAL POSTER CODE WITH HIS SOLUTION
### It seems no longer relevant since App1 and App2 have their own buttons.
#def button1_click():
# """ This is for the BMI Calculator Widget """
# root = Tk()
# app = App1(master=root)
# app.mainloop()
#
#def button2_click():
# """ This is for the Feet to Meters Conversion Widget """
# 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()
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()
if __name__ == '__main__':
main()
The application doesn't quit when the "Quit" button is pressed. Only the individual frames quit.
Thanks to Martineau for the hint that helped me get this example to work. I declared 'window as a global variable, since it was defined in the name space of the class constructors. Without that, there was an error raised of undefined window. This method breaks the encapsulation and modularity of the classes by passing in the window as a global. If there is a better way to do this, I would like to know.
# -*- coding: utf-8 -*-
""" Created on Thu Jul 11 17:20:22 2019
Filename: tkinter-multiple-frames-windows_v3.py
From question on StackOverflow question "ttk tkinter multiple frames/windows"
at https://stackoverflow.com/questions/6035101/ttk-tkinter-multiple-frames-windows?rq=1
Now a full example that works but it needed some modification to clarify how it works.
"""
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
class BMICalcApp(ttk.Frame):
""" This application calculates BMI and returns a value. """
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.createWidgets()
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="Ok", command=self.calculateBmi).grid(row=3, column=2, sticky=E)
self.button2 = ttk.Button(self, text="Cancel/Quit", command=window.destroy).grid(row=3, column=1, 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("")
class ConvertFeetMeters(ttk.Frame):
""" Application to convert feet to meters or vice versa. """
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
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.calculateButton = ttk.Button(self, text="Calculate", command=self.convert_feet_to_meters).grid(row=2, column=2, sticky=(S,E))
self.quitButton = ttk.Button(self, text="Quit", command=window.destroy).grid(row=2, column=1, 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 main():
#Setup Tk()
global window
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
bmi_calc = BMICalcApp(master=frame1)
bmi_calc.grid()
feet_meters_calc = ConvertFeetMeters(master=frame2)
feet_meters_calc.grid()
#Main loop
window.mainloop()
if __name__ == '__main__':
main()
I am totally new to tkinter. I am trying to pass data between two windows. There is a button on root window. button press will open a top level. There are two entry fields and a submit button in on toplevel window. user can enter two number and submit. What i am trying to achieve is, pressing submit button should close the top level and result (sum) should be shown in the root window. How to pass entry field data to root window?
from tkinter import *
root= Tk()
root.geometry('600x400')
sum_var= StringVar()
def entry_Fn():
level_1 = Toplevel(root)
Label( level_1, text = "level one").pack()
entry_1 =Entry(level_1)
entry_1.pack()
entry_2 =Entry(level_1)
entry_2.pack()
Button(level_1, text= "submit", command= submitBtn ).pack()
def submitBtn():
val_1= entry_1.get()
val_2= entry_2.get()
sum_var.set(int(val_1)+ int(val_2))
Label(root, text = "Main window").pack()
Button(root, text= "To enter Data", command= entry_Fn).pack()
sum = Label(root, textvariable = sum_var)
sum.pack()
root.mainloop()
#result
val_1= entry_1.get()
NameError: name 'entry_1' is not defined
#shall I define some global variables?
In this case, you don't have to declare global. Simply indent your submitBtn function inside entry_Fn:
def entry_Fn():
level_1 = Toplevel(root)
Label( level_1, text = "level one").pack()
entry_1 = Entry(level_1)
entry_1.pack()
entry_2 = Entry(level_1)
entry_2.pack()
def submitBtn():
val_1= entry_1.get()
val_2= entry_2.get()
sum_var.set(int(val_1)+ int(val_2))
level_1.destroy()
Button(level_1, text= "submit", command=submitBtn).pack()
But generally it is easier to make a class so you can avoid this kind of scope problems, like below:
from tkinter import *
class GUI(Tk):
def __init__(self):
super().__init__()
self.geometry('600x400')
self.sum_var= StringVar()
Label(self, text="Main window").pack()
Button(self, text="To enter Data", command=self.entry_Fn).pack()
sum = Label(self, textvariable=self.sum_var)
sum.pack()
def entry_Fn(self):
self.level_1 = Toplevel(self)
Label(self.level_1, text = "level one").pack()
self.entry_1 = Entry(self.level_1)
self.entry_1.pack()
self.entry_2 = Entry(self.level_1)
self.entry_2.pack()
Button(self.level_1, text="submit", command=self.submitBtn).pack()
def submitBtn(self):
val_1 = self.entry_1.get()
val_2 = self.entry_2.get()
self.sum_var.set(int(val_1)+ int(val_2))
self.level_1.destroy()
root = GUI()
root.mainloop()
For your case, you can simply pass the two entries to submitBtn() function:
def submitBtn(entry_1, entry_2):
....
Then update the command= for the submit button inside entry_Fn():
Button(level_1, text="submit", command=lambda: submitBtn(entry_1, enter_2)).pack()
You can subclass tk.TopLevel, and use a tk.IntVar to transfer the data back to root:
import tkinter as tk
class EntryForm(tk.Toplevel):
def __init__(self, master, sum_var):
super().__init__(master)
tk.Label(self, text="level one").pack()
self.sum_var = sum_var
self.entry_1 = tk.Entry(self)
self.entry_1.pack()
self.entry_2 = tk.Entry(self)
self.entry_2.pack()
tk.Button(self, text="submit", command=self.submitBtn).pack()
def submitBtn(self):
val_1 = self.entry_1.get()
val_2 = self.entry_2.get()
self.sum_var.set(int(val_1) + int(val_2))
self.destroy()
def spawn_entry_popup():
EntryForm(root, sum_var)
root= tk.Tk()
root.geometry('600x400')
sum_var = tk.IntVar()
tk.Label(root, text = "Main window").pack()
tk.Button(root, text= "To enter Data", command=spawn_entry_popup).pack()
sum_label = tk.Label(root, textvariable=sum_var)
sum_label.pack()
root.mainloop()
You can also place your app inside a class:
import tkinter as tk
class EntryForm(tk.Toplevel):
def __init__(self, master, sum_var):
super().__init__(master)
tk.Label(self, text="level one").pack()
self.sum_var = sum_var
self.entry_1 = tk.Entry(self)
self.entry_1.pack()
self.entry_2 = tk.Entry(self)
self.entry_2.pack()
tk.Button(self, text="submit", command=self.submitBtn).pack()
def submitBtn(self):
val_1 = self.entry_1.get()
val_2 = self.entry_2.get()
self.sum_var.set(int(val_1) + int(val_2))
class GUI(tk.Tk):
def __init__(self):
super().__init__()
self.geometry('600x400')
self.sum_var = tk.IntVar()
tk.Label(self, text = "Main window").pack()
tk.Button(self, text= "To enter Data", command=self.spawn_entry_popup).pack()
sum_label = tk.Label(self, textvariable=self.sum_var)
sum_label.pack()
def spawn_entry_popup(self):
EntryForm(self, self.sum_var)
GUI().mainloop()
I'm putting widgets into a popup for my GUI. I'm putting the checkboxes along the top of the pop up and I want the label, entry and button to be in a row below them. Whatever I try the label, entry and button always go next to the check boxes. I haven't found a solution which uses pack(). I've tried anchor=but this also didn't do what I wanted.
This is my code:
import tkinter as tk
from tkinter import *
CheckVar1 = IntVar()
CheckVar2 = IntVar()
class PopUp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
popup = tk.Toplevel(self, background='gray15')
popup.wm_title("EMAIL")
self.withdraw()
popup.tkraise(self)
self.c1 = tk.Checkbutton(popup, text="Current", variable=CheckVar1, onvalue =1, offvalue = 0, height=2, width=15)
self.c1.pack(side="left", fill="x")
self.c2 = tk.Checkbutton(popup, text="-1", variable=CheckVar2, onvalue =1, offvalue = 0, height=2, width=15)
self.c2.pack(side="left", fill="x")
label = tk.Label(popup, text="Please Enter Email Address", background='gray15', foreground='snow')
label.pack(side="left", fill="x", pady=10, padx=10)
self.entry = tk.Entry(popup, bd=5, width=35, background='gray30', foreground='snow')
self.entry.pack(side="left", fill="x")
self.button = tk.Button(popup, text="OK", command=self.on_button, background='gray15', foreground='snow')
self.button.pack(side="left", padx=10)
def on_button(self):
address = self.entry.get()
print(address)
time.sleep(10)
self.destroy()
app = PopUp()
app.mainloop
Is there something I can put into pack() so that I can put the widgets next to each other and then put the other below them?
Thanks in advance
Use the grid geometry manager to divide your window into two frames, then pack your widgets into the frames.
from tkinter import *
import time
class PopUp(Tk):
def __init__(self):
Tk.__init__(self)
CheckVar1 = IntVar()
CheckVar2 = IntVar()
popup = Toplevel(self, background='gray15')
popup.wm_title("EMAIL")
self.withdraw()
popup.tkraise(self)
topframe = Frame(popup)
topframe.grid(column=0, row=0)
bottomframe = Frame(popup)
bottomframe.grid(column=0, row=1)
self.c1 = Checkbutton(topframe, text="Current", variable=CheckVar1, onvalue=1, offvalue=0, height=2, width=15)
self.c1.pack(side="left", fill="x")
self.c2 = Checkbutton(topframe, text="-1", variable=CheckVar2, onvalue=1, offvalue=0, height=2, width=15)
self.c2.pack(side="left", fill="x")
label = Label(bottomframe, text="Please Enter Email Address", background='gray15', foreground='snow')
label.pack(side="left", fill="x", pady=10, padx=10)
self.entry = Entry(bottomframe, bd=5, width=35, background='gray30', foreground='snow')
self.entry.pack(side="left", fill="x")
self.button = Button(bottomframe, text="OK", command=self.on_button, background='gray15', foreground='snow')
self.button.pack(side="left", padx=10)
def on_button(self):
address = self.entry.get()
print(address)
time.sleep(10)
self.destroy()
app = PopUp()
app.mainloop()
A few notes:
There is no need to import Tkinter twice
Mainloop is a method, so it's app.mainloop()
CheckVar1 and CheckVar2 must be declared within your class
camel case (capitalising within words, e.g 'CheckVar') is not pythonic
I have the following code to generate a two entry input dialog box and a button to close the "app".
However I cannot cannot get the values out of the outputs. They always come out as x and N. The code was not developed by me since I am a beginner with python. Can anyone give me hand with this?
from tkinter import Tk, Text, TOP, BOTH, X, N, LEFT, RIGH
from tkinter.ttk import Frame, Label, Entry, Button
class SimpleDialog(Frame):
def __init__(self):
super().__init__()
self.output1 = ""
self.output2 = ""
self.initUI()
def initUI(self):
self.master.title("Simple Dialog")
self.pack(fill=BOTH, expand=True)
frame1 = Frame(self)
frame1.pack()
lbl1 = Label(frame1, text="Input1", width=6)
lbl1.pack(side=LEFT, padx=5, pady=10)
self.entry1 = Entry(frame1)
self.entry1.pack(padx=5, expand=True)
frame2 = Frame(self)
frame2.pack()
lbl2 = Label(frame2, text="Input2", width=6)
lbl2.pack(side=LEFT, padx=5, pady=10)
self.entry2 = Entry(frame2)
self.entry2.pack(padx=5, expand=True)
frame3 = Frame(self)
frame3.pack()
btn = Button(frame3, text="Submit", command=self.onSubmit)
btn.pack(padx=5, pady=10)
def onSubmit(self):
self.output1 = self.entry1.get()
self.output2 = self.entry2.get()
self.quit()
def main():
# This part triggers the dialog
root = Tk()
root.geometry("250x150+300+300")
app = SimpleDialog()
root.mainloop()
user_input = (app.output1, app.output2)
try:
root.destroy()
except:
pass
return user_input
if __name__ == '__main__':
main()
kind regards!
I need to return all variables from all tabs by clicking on ok button.
I have two tabs. What I want is that when I enter some value in 2nd tab, it should automatically appear in first tab in 'height' entry.
Then if I click 'ok' in first tab, it should return all variables(from first tab and 2nd tab) to my 'main' program for further use.
Thanks
from tkinter import *
from tkinter import ttk
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():
#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()
main()
You have some fundamental mistakes in your program -- you cannot have three mainloops running at the same. You should always only have exactly one instance of Tk, and call mainloop exactly once.
Regardless of that, the solution is that you need to create a method or public variable in the app, and then your button callback needs to be able to call that method or access that variable.
For example, you would do it like this:
def callback():
value1 = app1.getValue()
value2 = app2.getValue()
...