Related
I am having an issue getting text to show on Tkinter buttons. I don't get any errors so im not sure why this is the case, I will post the full working code below if anyone can see any obvius errors.I have never had any problems with button labels before but I am trying a new layout with dropdown tabs so this could be a reason for the issue.
import tkinter as tk
from tkinter import ttk
class ToggledFrame(tk.Frame):
def __init__(self, parent, text="", *args, **options):
tk.Frame.__init__(self, parent, *args, **options)
root.state('zoomed')
root.configure(background='black')
root.title("Stylibleue dashboard")
self.show = tk.IntVar()
self.show.set(0)
self.title_frame = ttk.Frame(self)
self.title_frame.pack(fill="x", expand=1)
ttk.Label(self.title_frame, text=text).pack(side="left", fill="x")
self.toggle_button = ttk.Checkbutton(self.title_frame, width=1, text='+',
command=self.toggle,
variable=self.show, style='Toolbutton')
self.toggle_button.pack(side="left", fill="x", expand=1)
self.sub_frame = tk.Frame(self, relief="sunken", borderwidth=1)
def toggle(self):
if bool(self.show.get()):
self.sub_frame.pack(fill="x", expand=1)
self.toggle_button.configure(text='-')
else:
self.sub_frame.forget()
self.toggle_button.configure(text='+')
def helloCallBack (self):
print ("hello")
if __name__ == "__main__":
root = tk.Tk()
t = ToggledFrame(root, text='Bassin 1', relief="raised")
t.pack(fill="x", anchor="s")
B = ttk.Button(t.sub_frame, text ='Feeder 1',command = quit)
ttk.Button(t.sub_frame).pack( expand=0, pady=2, padx=2, anchor="w")
c = ttk.Button(t.sub_frame, text ="Feeder 2")
ttk.Button(t.sub_frame).pack(expand=0, pady=2, padx=2, anchor="w")
t2 = ToggledFrame(root, text='Bassin 2', relief="raised")
t2.pack(fill="x")
d = ttk.Button(t2.sub_frame, text ='Feeder 1',command = quit)
ttk.Button(t2.sub_frame).pack( expand=0, pady=2, padx=2, anchor="w")
e = ttk.Button(t2.sub_frame, text ="Feeder 2")
ttk.Button(t2.sub_frame).pack(expand=0, pady=2, padx=2, anchor="w")
root.mainloop()
You are creating 8 buttons but only giving a label to four of them, and it’s the ones without a label that you are calling .pack on. The ones with the label are never added to the window.
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'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 written a code in python 2.7 and i have created a root window with two buttons: submit and cancel when i press submit button, a new window opens and previous parent/root window gets iconify. Now i want that when i cut the child window, parent window should be deiconify, i am in a trouble that where to put the condition so that parent window gets deiconify?
from Tkinter import *
root = Tk()
root.title("test window")
root.geometry('400x220+500+250')
root.configure(background="dark gray")
def submit(*args):
root.iconify()
popup_root_window = Toplevel()
popup_root_window.geometry('300x50+550+300')
popup_root_window.resizable(width=False, height=False)
popup_root_window.focus_force()
popup_root_window.grab_set()
popup_root_window_label = Label(popup_root_window, text="new window open successfully.")
popup_root_window_label.pack(anchor=CENTER, padx=10, pady=20)
frame = Frame(root, bd=4, relief="raise", height=100, width=250)
frame.pack(fill="both", padx=70, pady=35)
frame.pack_propagate(0)
submit_button = Button(frame, text="Submit", command=submit, width=10)
submit_button.grid(row=0, column=0)
cancel_button = Button(frame, text="Cancel", width=10)
cancel_button.grid(row=0, column=1)
root.mainloop()
I wrote the below in 3.6 but it should still work in 2.7.
from tkinter import *
class App:
def __init__(self, root):
self.root = root
self.label1 = Label(self.root, text="I'm your main window.")
self.button = Button(self.root, text="Submit", command=self.command)
self.label1.pack()
self.button.pack()
def command(self):
self.root.iconify()
self.top = Toplevel(self.root)
self.label2 = Label(self.top, text="I'm your toplevel window.")
self.label2.pack()
self.top.protocol("WM_DELETE_WINDOW", self.close)
def close(self):
self.top.destroy()
self.root.deiconify()
root = Tk()
App(root)
root.mainloop()
You can use .protocol() on the event WM_DELETE_WINDOW to create a callback whenever the X is selected from the title bar of the designated window.
This is tested and working with Python 3.6 on Windows 10.
You can try this one. i have tested this in python 2.7.13 and it working correctly.
from Tkinter import *
root = Tk()
root.title("test window")
root.geometry('400x220+500+250')
root.configure(background="dark gray")
def submit(*args):
def on_closing(*args):
popup_root_window.destroy()
root.deiconify()
root.iconify()
popup_root_window = Toplevel()
popup_root_window.geometry('300x50+550+300')
popup_root_window.resizable(width=False, height=False)
popup_root_window.focus_force()
popup_root_window.grab_set()
popup_root_window_label = Label(popup_root_window, text="new window open successfully.")
popup_root_window_label.pack(anchor=CENTER, padx=10, pady=20)
popup_root_window.protocol("WM_DELETE_WINDOW", on_closing)
frame = Frame(root, bd=4, relief="raise", height=100, width=250)
frame.pack(fill="both", padx=70, pady=35)
frame.pack_propagate(0)
submit_button = Button(frame, text="Submit", command=submit, width=10)
submit_button.grid(row=0, column=0)
cancel_button = Button(frame, text="Cancel", width=10)
cancel_button.grid(row=0, column=1)
root.mainloop()
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()
...