I have a program where the main window is divided into two sections each section has a collection of forms (simple label/input columns). The default is 4 of these columns in the first section and 2 in the second section. I would like the user to be able to change this ratio. I think I have all of the programming in place to do this, I just can't get the main window to redraw with the correct structure. Any help would be much appreciated. Thanks.
I like the simplicity and idea behind your example, however, I'm modifying some legacy code and don't have the time to rewrite my layouts as definitions. I tried to create a def that would simply do grid_columnconfig(), but that didn't work. I've reduced the code so that it looks like what I'm working with and it is also functional. If you change the variable 'max_pol_modules' it adjusts columns on the left versus columns on the right, so, I'm trying to change this variable through an interface widget and redraw.
from Tkinter import *
import tkFont
max_pol_modules = 3
max_bus_modules = 6 - max_pol_modules
tech_green = '#5E9732'
button_grey = '#666666'
grey = '#777777'
def config1():
global max_pol_modules, max_bus_modules
max_pol_modules = 1
max_bus_modules = 6 - max_pol_modules
# print max_bus_modules
# left_frame.update()
def config2():
global max_pol_modules, max_bus_modules
max_pol_modules = 2
max_bus_modules = 6 - max_pol_modules
# print max_bus_modules
def config3():
global max_pol_modules, max_bus_modules
max_pol_modules = 3
max_bus_modules = 6 - max_pol_modules
# print max_bus_modules
def config4():
global max_pol_modules, max_bus_modules
max_pol_modules = 4
max_bus_modules = 6 - max_pol_modules
# print max_bus_modules
def about():
box.showinfo("About GUI","GE Bus Converter and Point of Load GUI")
def bar(frame, row, span):
"create a bar to separate a section"
x = Frame(frame, relief=GROOVE, bd=2, width=86*(span+1), height=2)
x.grid(row=row, column=0, columnspan=10, pady=7, sticky=S+E)
x.grid_propagate(0)
def bar2(frame, row, span):
"create a bar to separate a section"
x = Frame(frame, relief=GROOVE, bd=2, width=86*(span+1), height=2)
x.grid(row=row, column=0, columnspan=10, pady=3, sticky=S+E)
x.grid_propagate(0)
def bar3(frame, row, span):
"create a bar to separate a section"
x = Frame(frame, relief=GROOVE, bd=2, width=100, height=2)
x.grid(row=row, column=0, columnspan=10, pady=7, sticky=S+E)
x.grid_propagate(0)
root = Tk()
menubar = Menu(root)
submenu=Menu(menubar,tearoff=0)
submenu2=Menu(submenu,tearoff=0)
submenu2.add_command(label="1 - 5", command=config1)
submenu2.add_command(label="2 - 4", command=config2)
submenu2.add_command(label="3 - 3", command=config3)
submenu2.add_command(label="4 - 2", command=config4)
submenu_help = Menu(submenu,tearoff=0)
submenu_help.add_command(label="About",command=about)
submenu.add_cascade(label="Change Configuration",menu=submenu2)
submenu.add_command(label="Exit", command=root.quit)
menubar.add_cascade(label="Settings",menu=submenu)
menubar.add_cascade(label="Help", menu=submenu_help)
# display the menu
root.config(menu=menubar)
entry_wid = 6
small_font = tkFont.Font(family='Arial', size=8, weight='bold')
lite_font = tkFont.Font(family='Arial', size=9)
large_font = tkFont.Font(family='Arial', size=9)
heading_font = tkFont.Font(family='Arial', size=10, weight='bold')
button_font = tkFont.Font(family='Arial', size=8, weight='bold')
root.option_add('*font', lite_font)
root.option_add('*background', '#C2C2C4')
root.option_add('*Label.font', small_font)
root.option_add('*Entry.background', 'white')
root.option_add('*Button.font', button_font)
root.option_add('*Button.background', button_grey)
root.option_add('*Button.foreground', 'yellow')
root.option_add('*Text.background', 'white')
root.option_add('*Text.font', small_font)
root.option_add('*ScrolledText.font', lite_font)
left_frame = Frame(root)
right_frame = Frame(root)
pol_frame = Frame(left_frame, bd=2, relief=SUNKEN)
x = Label(pol_frame, text="POL Address", anchor=E)
x.grid(row=0, column=0, sticky=E)
x = Label(pol_frame, text="Rtrim (Kohms)", anchor=E)
x.grid(row=1, column=0, sticky=E)
x = Label(pol_frame, text="Nominal Vout (V)", anchor=E)
x.grid(row=2, column=0, sticky=E)
bar2(pol_frame, 0, max_pol_modules)
module_address = []
module_i2c = []
module_status = []
module_resistor = []
module_vout_nominal = []
for i in range(max_pol_modules):
# Module ID and address
f = Frame(pol_frame)
x = Label(f, text=i+1)
x.grid(row=0, column=0)
v = StringVar()
x = Entry(f, textvariable=v, width=3, justify=CENTER)
x.grid(row=0, column=1)
f.grid(row=0, column=i+1, pady=8, padx=20)
module_address.append(v)
module_i2c.append("")
module_status.append(0)
# module resistor
v = StringVar()
x = Entry(pol_frame, textvariable=v, width=entry_wid, justify=CENTER)
f = lambda event, module=i: change_resistor_event(event, module)
g = lambda value, m=i, o=16: set_change(value, m, o)
x.bind("<KeyRelease>", f, "+")
x.bind("<KeyRelease>", g, "+")
x.bind("<FocusOut>", f, "+")
x.grid(row=1, column=i+1, pady=0)
module_resistor.append(v)
# module nominal vout
v = StringVar()
x = Label(pol_frame, textvariable=v, width=entry_wid-1,
relief=SUNKEN, bg='#DDDDDD', font=lite_font)
x.grid(row=2, column=i+1, pady=0)
module_vout_nominal.append(v)
bus_frame = Frame(left_frame, bd=2, relief=SUNKEN)
#x = Label(bus_frame, text="Module (address)", anchor=E)
#x.grid(row=0, column=max_pol_modules+1, sticky=E)
x = Label(bus_frame, text="Bus Conv Address", anchor=E)
x.grid(row=0, column=0, sticky=E)
config_bus = []
r = 0
#for i in range(max_pol_modules,max_pol_modules+max_bus_modules):
for i in range(max_bus_modules):
# Module ID and address
f = Frame(bus_frame)
x = Label(f, text=i+5)
x.grid(row=0, column=0)
v = StringVar()
x = Entry(f, textvariable=v, width=3, justify=CENTER)
x.grid(row=0, column=1)
f.grid(row=0, column=i+2, pady=8, padx=20)
module_address.append(v)
module_i2c.append("")
module_status.append(0)
bar2(bus_frame, r, max_bus_modules)
r += 1
# the measured values
measure_info = ["Vout (V)", "Iout (A)", "Vin (V)", "Temp (degC)"]
measures_bus = []
for mi in measure_info:
x = Label(bus_frame, text=mi, anchor=E)
x.grid(row=r, column=0, sticky=E)
m = []
for j in range(max_bus_modules):
v = StringVar()
x = Label(bus_frame, textvariable=v, width=entry_wid-1,
relief=SUNKEN, bg='#DDDDDD', font=lite_font)
x.grid(row=r, column=j+2)
m.append(v)
measures_bus.append(m)
r += 1
pol_frame.grid(row=0, column=0, sticky=N+W)
bus_frame.grid(row=0, column=1, sticky=N+W)
left_frame.grid(row=0, column=0, sticky=N)
right_frame.grid(row=0, column=1, sticky=N)
root.mainloop()
Edited Example where form[4] and form[5] need to be deleted.
import Tkinter as tk
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.forms = []
self.toolbar = tk.Frame(self)
self.toolbar.pack(side="top", fill="x", expand=False)
button2 = tk.Button(self.toolbar, text="2 columns", command=self.layout2col)
button3 = tk.Button(self.toolbar, text="3 columns", command=self.layout3col)
button2.pack(side="left")
button3.pack(side="left")
self.forms_frame = tk.Frame(self, borderwidth=2, relief="groove")
self.forms_frame.pack(side="top", fill="both", expand="True", padx=2, pady=2)
for i in range(6):
frame = tk.LabelFrame(self.forms_frame, text="Form %s" % i)
self.forms.append(frame)
label = tk.Label(frame, text="Field %s" % i)
entry = tk.Entry(frame, width=20)
label.pack(side="left", fill="y")
entry.pack(side="left", fill="both", expand=True)
self.layout2col()
def layout3col(self):
self.forms[0].grid(column=0, row=0, padx=4, pady=2, sticky="ew")
self.forms[1].grid(column=0, row=1, padx=4, pady=2, sticky="ew")
self.forms[2].grid(column=1, row=0, padx=4, pady=2, sticky="ew")
self.forms[3].grid(column=1, row=1, padx=4, pady=2, sticky="ew")
self.forms[4].grid(column=2, row=0, padx=4, pady=2, sticky="ew")
self.forms[5].grid(column=2, row=1, padx=4, pady=2, sticky="ew")
self.forms_frame.grid_columnconfigure(0, weight=1)
self.forms_frame.grid_columnconfigure(1, weight=1)
self.forms_frame.grid_columnconfigure(2, weight=1)
def layout2col(self):
self.forms[0].grid(column=0, row=0, padx=4, pady=2, sticky="ew")
self.forms[1].grid(column=0, row=1, padx=4, pady=2, sticky="ew")
self.forms[2].grid(column=1, row=0, padx=4, pady=2, sticky="ew")
self.forms[3].grid(column=1, row=1, padx=4, pady=2, sticky="ew")
self.forms_frame.grid_columnconfigure(0, weight=1)
self.forms_frame.grid_columnconfigure(1, weight=1)
self.forms_frame.grid_columnconfigure(2, weight=0)
if __name__ == "__main__":
app = App()
app.mainloop()
Since you are using the grid geometry manager, you just need to use the grid method to place them in their new rows and columns. You may need to also call rowconfigure and/or columnconfigure to attach appropriate weights to the new rows and columns.
Here's a bit of a contrived example showing the general principle. It could be more efficient but hopefully it gives you a rough idea:
import Tkinter as tk
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.forms = []
self.toolbar = tk.Frame(self)
self.toolbar.pack(side="top", fill="x", expand=False)
button2 = tk.Button(self.toolbar, text="2 columns", command=self.layout2col)
button3 = tk.Button(self.toolbar, text="3 columns", command=self.layout3col)
button2.pack(side="left")
button3.pack(side="left")
self.forms_frame = tk.Frame(self, borderwidth=2, relief="groove")
self.forms_frame.pack(side="top", fill="both", expand="True", padx=2, pady=2)
for i in range(6):
frame = tk.LabelFrame(self.forms_frame, text="Form %s" % i)
self.forms.append(frame)
label = tk.Label(frame, text="Field %s" % i)
entry = tk.Entry(frame, width=20)
label.pack(side="left", fill="y")
entry.pack(side="left", fill="both", expand=True)
self.layout2col()
def layout3col(self):
self.forms[0].grid(column=0, row=0, padx=4, pady=2, sticky="ew")
self.forms[1].grid(column=0, row=1, padx=4, pady=2, sticky="ew")
self.forms[2].grid(column=1, row=0, padx=4, pady=2, sticky="ew")
self.forms[3].grid(column=1, row=1, padx=4, pady=2, sticky="ew")
self.forms[4].grid(column=2, row=0, padx=4, pady=2, sticky="ew")
self.forms[5].grid(column=2, row=1, padx=4, pady=2, sticky="ew")
self.forms_frame.grid_columnconfigure(0, weight=1)
self.forms_frame.grid_columnconfigure(1, weight=1)
self.forms_frame.grid_columnconfigure(2, weight=1)
def layout2col(self):
self.forms[0].grid(column=0, row=0, padx=4, pady=2, sticky="ew")
self.forms[1].grid(column=0, row=1, padx=4, pady=2, sticky="ew")
self.forms[2].grid(column=0, row=2, padx=4, pady=2, sticky="ew")
self.forms[3].grid(column=1, row=0, padx=4, pady=2, sticky="ew")
self.forms[4].grid(column=1, row=1, padx=4, pady=2, sticky="ew")
self.forms[5].grid(column=1, row=2, padx=4, pady=2, sticky="ew")
self.forms_frame.grid_columnconfigure(0, weight=1)
self.forms_frame.grid_columnconfigure(1, weight=1)
self.forms_frame.grid_columnconfigure(2, weight=0)
if __name__ == "__main__":
app = App()
app.mainloop()
You've probably already tried this, but can you call update() on your root widget?
You might also need to pack() again, first.
Related
Every time I click on the buttons I get a error. Could anyone help me by providing a fix or telling me what the issue was because I cant see the issue.
Whenever the button is clicked it is supposed to open a new page and the side bar on the left with the buttons in should stay where they are at.
import tkinter
import tkinter.messagebox
import customtkinter
customtkinter.set_appearance_mode("dark")
customtkinter.set_default_color_theme("dark-blue")
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
# configure window
self.title("Opium")
self.geometry(f"{1100}x{580}")
# configure grid layout (4x4)
self.grid_columnconfigure(1, weight=1)
self.grid_columnconfigure((2, 3), weight=0)
self.grid_rowconfigure((0, 1, 2), weight=1)
# create sidebar frame with widgets
self.content_label = customtkinter.CTkLabel(self, text="", font=customtkinter.CTkFont(size=30, weight="bold"))
self.content_label.grid(row=0, column=1, rowspan=4, sticky="nsew", padx=(10, 0), pady=(20, 10))
self.sidebar_frame = customtkinter.CTkFrame(self, width=140, corner_radius=0)
self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew")
self.sidebar_frame.grid_rowconfigure(4, weight=1)
self.logo_label = customtkinter.CTkLabel(self.sidebar_frame, text="Opium", font=customtkinter.CTkFont(size=30, weight="bold"))
self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10))
self.sidebar_button_1 = customtkinter.CTkButton(self.sidebar_frame, text="Button 1", command=self.sidebar_button_event)
self.sidebar_button_1.grid(row=1, column=0, padx=20, pady=10)
self.sidebar_button_2 = customtkinter.CTkButton(self.sidebar_frame, text="Button 2", command=self.sidebar_button_event)
self.sidebar_button_2.grid(row=2, column=0, padx=20, pady=10)
self.sidebar_button_3 = customtkinter.CTkButton(self.sidebar_frame, text="Button 3", command=self.sidebar_button_event)
self.sidebar_button_3.grid(row=3, column=0, padx=20, pady=10)
self.appearance_mode_label = customtkinter.CTkLabel(self.sidebar_frame, text="Appearance Mode:", anchor="w")
self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0))
self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self.sidebar_frame, values=["Light", "Dark", "System"],
command=self.change_appearance_mode_event)
self.appearance_mode_optionemenu.grid(row=6, column=0, padx=20, pady=(10, 10))
def open_input_dialog_event(self):
dialog = customtkinter.CTkInputDialog(text="Type in a number:", title="CTkInputDialog")
print("CTkInputDialog:", dialog.get_input())
def change_appearance_mode_event(self, new_appearance_mode: str):
customtkinter.set_appearance_mode(new_appearance_mode)
def change_scaling_event(self, new_scaling: str):
new_scaling_float = int(new_scaling.replace("%", "")) / 100
customtkinter.set_widget_scaling(new_scaling_float)
def sidebar_button_event(self):
try:
self.right_frame.destroy()
except AttributeError:
pass
self.right_frame = customtkinter.CTkFrame(self, bg="white", width=900, height=580)
self.right_frame.grid(row=0, column=1, rowspan=3, columnspan=2, sticky="nsew")
self.home_label = customtkinter.CTkLabel(self.right_frame, text="Home", font=customtkinter.CTkFont(size=30, weight="bold"), bg="white")
self.home_label.pack(side="top", fill="both", padx=20, pady=20)
if __name__ == "__main__":
app = App()
app.mainloop()
I have tested the code and the error you are getting when clicking the buttons is
ValueError: ['bg'] are not supported arguments. Look at the documentation for supported arguments.
As the error already says, bg is not a supported argument by customtkinter.
https://github.com/TomSchimansky/CustomTkinter/wiki/CTkLabel#arguments
In your specific case you have to change the two instances of bg="white" to bg_color="white".
import tkinter
import tkinter.messagebox
import customtkinter
customtkinter.set_appearance_mode("dark")
customtkinter.set_default_color_theme("dark-blue")
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
# configure window
self.title("Opium")
self.geometry(f"{1100}x{580}")
# configure grid layout (4x4)
self.grid_columnconfigure(1, weight=1)
self.grid_columnconfigure((2, 3), weight=0)
self.grid_rowconfigure((0, 1, 2), weight=1)
# create sidebar frame with widgets
self.content_label = customtkinter.CTkLabel(
self, text="", font=customtkinter.CTkFont(size=30, weight="bold"))
self.content_label.grid(
row=0, column=1, rowspan=4, sticky="nsew", padx=(10, 0), pady=(20, 10))
self.sidebar_frame = customtkinter.CTkFrame(
self, width=140, corner_radius=0)
self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew")
self.sidebar_frame.grid_rowconfigure(4, weight=1)
self.logo_label = customtkinter.CTkLabel(
self.sidebar_frame, text="Opium", font=customtkinter.CTkFont(size=30, weight="bold"))
self.logo_label.grid(row=0, column=0, padx=20, pady=(20, 10))
self.sidebar_button_1 = customtkinter.CTkButton(
self.sidebar_frame, text="Button 1", command=self.sidebar_button_event)
self.sidebar_button_1.grid(row=1, column=0, padx=20, pady=10)
self.sidebar_button_2 = customtkinter.CTkButton(
self.sidebar_frame, text="Button 2", command=self.sidebar_button_event)
self.sidebar_button_2.grid(row=2, column=0, padx=20, pady=10)
self.sidebar_button_3 = customtkinter.CTkButton(
self.sidebar_frame, text="Button 3", command=self.sidebar_button_event)
self.sidebar_button_3.grid(row=3, column=0, padx=20, pady=10)
self.appearance_mode_label = customtkinter.CTkLabel(
self.sidebar_frame, text="Appearance Mode:", anchor="w")
self.appearance_mode_label.grid(row=5, column=0, padx=20, pady=(10, 0))
self.appearance_mode_optionemenu = customtkinter.CTkOptionMenu(self.sidebar_frame, values=["Light", "Dark", "System"],
command=self.change_appearance_mode_event)
self.appearance_mode_optionemenu.grid(
row=6, column=0, padx=20, pady=(10, 10))
def open_input_dialog_event(self):
dialog = customtkinter.CTkInputDialog(
text="Type in a number:", title="CTkInputDialog")
print("CTkInputDialog:", dialog.get_input())
def change_appearance_mode_event(self, new_appearance_mode: str):
customtkinter.set_appearance_mode(new_appearance_mode)
def change_scaling_event(self, new_scaling: str):
new_scaling_float = int(new_scaling.replace("%", "")) / 100
customtkinter.set_widget_scaling(new_scaling_float)
def sidebar_button_event(self):
try:
self.right_frame.destroy()
except AttributeError:
pass
self.right_frame = customtkinter.CTkFrame(
self, bg_color="white", width=900, height=580)
self.right_frame.grid(row=0, column=1, rowspan=3,
columnspan=2, sticky="nsew")
self.home_label = customtkinter.CTkLabel(
self.right_frame, text="Home", font=customtkinter.CTkFont(size=30, weight="bold"), bg_color="white")
self.home_label.pack(side="top", fill="both", padx=20, pady=20)
if __name__ == "__main__":
app = App()
app.mainloop()
For the next time please be so kind and include the error message you are getting with your question
I'm making a game based off of the periodic table with tkinter. I made the particle frame just fine, so I decided to copy the code and reuse it for the element frame, changing only the variable names. But for some reason, even though the particle frame works just fine, nothing shows up for the element frame. Here is my full code:
# Boilerplate
import random
import periodictable as pt
from tkinter import *
root = Tk()
root.title('Periodic Table Game')
root.geometry('350x250')
LightBlue = "#b3c7d6"
Menu = Frame(root)
elementFrame = Frame(root)
particleFrame = Frame(root)
settingsFrame = Frame(root)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
for AllFrames in (Menu, elementFrame, particleFrame, settingsFrame):
AllFrames.grid(row=0, column=0, sticky='nsew')
AllFrames.configure(bg=LightBlue)
def show_frame(frame):
frame.tkraise()
show_frame(Menu)
# Menu Frame
Menu.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
MenuTitle = Label(Menu, text="Periodic Table Game", font=("Arial", 15), bg=LightBlue)
MenuTitle.grid(row=0, column=0, pady=25)
MenuTitle.grid_rowconfigure(1, weight=1)
MenuTitle.grid_columnconfigure(1, weight=1)
MenuButton1 = Button(Menu, width=25, text="Guess The Particles", command=lambda: show_frame(particleFrame))
MenuButton1.grid(row=1, column=0)
MenuButton2 = Button(Menu, width=25, text="Guess The Element Name", command=lambda: show_frame(elementFrame))
MenuButton2.grid(row=2, column=0, pady=5)
SettingsButton = Button(Menu, width=25, text="Settings", command=lambda: show_frame(settingsFrame))
SettingsButton.grid(row=3, column=0)
# Particle Frame
particleFrame.grid_columnconfigure(0, weight=1)
BackButtonF2 = Button(particleFrame, text='Back', command=lambda: show_frame(Menu))
BackButtonF2.grid(row=0, column=0, sticky=W)
ParticleLabel = Label(particleFrame, text='testing', bg=LightBlue)
ParticleLabel.grid(row=1, column=0, pady=15)
ParticleEntry = Entry(particleFrame)
ParticleEntry.grid(row=2, column=0, pady=10)
ParticleEnter = Button(particleFrame, text='Enter', width=10)
ParticleEnter.grid(row=3, column=0, pady=10)
# Element Frame
elementFrame.grid_columnconfigure(0, weight=1)
BackButtonF3 = Button(particleFrame, text='Back', command=lambda: show_frame(Menu))
BackButtonF3.grid(row=0, column=0, sticky=W)
ElementLabel = Label(particleFrame, text='testing', bg=LightBlue)
ElementLabel.grid(row=1, column=0, pady=15)
ElementEntry = Entry(particleFrame)
ElementEntry.grid(row=2, column=0, pady=10)
ElementEnter = Button(particleFrame, text='Enter', width=10)
ElementEnter.grid(row=3, column=0, pady=10)
root.mainloop()
Why does identical code work only with one frame?
Precisely, because you copied the code you don't spot where the issue is.
When you are defining the element frame widgets you are placing them all into particleFrame.
Example:
BackButtonF3 = Button(particleFrame, text='Back', command=lambda: show_frame(Menu))
should be
BackButtonF3 = Button(elementFrame, text='Back', command=lambda: show_frame(Menu))
Your problem will be solved.
Change this particleFrame, to elementFrame
snippet code:
BackButtonF3 = Button(elementFrame, text='Back', command=lambda: show_frame(Menu))
BackButtonF3.grid(row=0, column=0, sticky=W)
ElementLabel = Label(elementFrame, text='testing', bg=LightBlue)
ElementLabel.grid(row=1, column=0, pady=15)
ElementEntry = Entry(elementFrame)
ElementEntry.grid(row=2, column=0, pady=10)
ElementEnter = Button(elementFrame, text='Enter', width=10)
ElementEnter.grid(row=3, column=0, pady=10)
Screenshot before:
Screenshot after same as elementFrame and particleFrame:
This is my code:
mycanvas = Canvas(self.search_result_frame)
mycanvas.pack(side=LEFT)
yscrollbar = ttk.Scrollbar(self.search_result_frame, orient="vertical", command=mycanvas.yview)
yscrollbar.pack(side=RIGHT, fill=Y)
mycanvas.configure(yscrollcommand=yscrollbar.set)
mycanvas.bind('<Configure>', lambda e: mycanvas.configure(scrollregion = mycanvas.bbox('all')))
self.sample_frame = Frame(mycanvas)
mycanvas.create_window((0,0), window=self.sample_frame, anchor=E)
for widget in self.search_result_frame.winfo_children():
widget.destroy()
if len(matching_bills) > 0:
for bill in matching_bills:
with open(f'{self.bill_folder}//{bill}//data//bill_details.json', 'r') as bill_json_file:
bill_details = json.loads(bill_json_file.read())
customer_name = bill_details["customer_details"][0]
payment_method = bill_details["payment_method"]
date_of_issue = bill_details["date_of_issue"]
date_of_issue = datetime.strptime(date_of_issue, "%d/%m/%Y")
date_of_issue = date_of_issue.strftime("%d %b %Y")
# # -------------------- Search Result Frame Contents
result_frame = Frame(self.sample_frame, bg=self.bg3, bd=5, relief=GROOVE)
result_frame.pack(fill=BOTH, pady=2)
result_billno_lbl = Label(result_frame, text=bill, bg=self.bg1, fg="#FFF", font=self.search_results_font1, padx=22, pady=3)
result_billno_lbl.grid(row=0, column=0, padx=50, pady=8, sticky=W)
billed_to_lbl = Label(result_frame, text=f"Billed To - {customer_name}", bg=self.bg1, fg="#FFF", font=self.search_results_font2, bd=2, relief=RAISED, padx=12, pady=3)
billed_to_lbl.grid(row=0, column=1, padx=80, sticky=W)
billed_type_lbl = Label(result_frame, text=f"Bill Type - {payment_method}", bg=self.bg1, fg="#FFF", font=self.search_results_font2, bd=2, relief=RAISED, padx=12, pady=3)
billed_type_lbl.grid(row=0, column=2, sticky=W)
issued_on_lbl = Label(result_frame, text=f"Issued On - {date_of_issue}", bg=self.bg1, fg="#FFF",
font=self.search_results_font2, bd=2, relief=RAISED, padx=12, pady=3)
issued_on_lbl.grid(row=0, column=3, padx=80, sticky=W)
view_btn = Button(result_frame, text="View", font="Comicsan 14", bd=2, relief=GROOVE, bg="#000", fg="#FFF", padx=1, command=lambda bill=bill: self.view_bill(bill))
view_btn.grid(row=0, column=4, padx=3, columnspan=2, sticky=W)
elif len(matching_bills) == 0:
for widgets in self.search_result_frame.winfo_children():
widgets.destroy()
no_result_lbl = Label(self.search_result_frame, text=f"No search result found for {bill_cat}", font=self.search_results_font1, bg=self.bg3, fg="#FFF")
no_result_lbl.pack(fill=X)
When I run it, it shows me the bad window path name ".!labelframe.!canvas.!frame error and when I try to do the same thing without object-oriented in tkinter then it works well !
I want to create a BMI calculator program with Tkinter but I'm stuck at calculation procedure
I use StringVar() to keep user data to calculate but I don't know how to calculate
this my code :
from tkinter import *
def mainwindow():
main = Tk()
main.geometry("300x400")
main.title("BMI")
main.rowconfigure((0,1,2,3,4), weight=1)
main.columnconfigure(0, weight=1)
main.config(bg="green")
main.option_add("*Font", "times 15 bold")
return main
def createframe(main):
Label(main, text="BMI APP", bg="lightgreen").grid(row=0, column=0, sticky=N)
frame_1 = Frame(main, bg="white")
frame_1.grid(row=1, column=0, sticky="NEWS", padx=10, pady=10, ipady=5)
frame_2 = Frame(main, bg="white")
frame_2.grid(row=2, column=0, sticky="NEWS", padx=10, pady=10, ipady=5)
frame_3 = Frame(main, bg="white")
frame_3.grid(row=3, column=0, sticky="NEWS", padx=10, pady=10, ipady=20)
frame_bottom = Frame(main, bg="white")
frame_bottom.grid(row=4, column=0, sticky="NEWS", padx=10, pady=10, ipady=20)
frame_bottom.columnconfigure(0, weight=0)
frame_bottom.columnconfigure(1, weight=2)
return frame_1, frame_2, frame_3, frame_bottom
def widget(frame_1, frame_2, frame_3, frame_bottom):
Label(frame_1, text="HEIGHT:(cm.)").grid(row=0, column=0, padx=5, pady=5, sticky=W)
ent_height = Entry(frame_1, bg="pink", textvariable=height_var)
ent_height.grid(row=1, column=0, ipadx=40, padx=10, sticky=N+W)
Label(frame_2, text="WEIGHT:(kg.)").grid(row=0, column=0, padx=5, pady=5, sticky=W)
ent_weight = Entry(frame_2, bg="lightblue", textvariable=weight_var)
ent_weight.grid(row=1, column=0, ipadx=40, padx=10, sticky=N+W)
Button(frame_bottom, text="Calculate", highlightbackground="lightgreen", fg="white", command=find_bmi).grid(row=2, column=1)
show_data = Label(frame_bottom, bg="white")
return ent_height, ent_weight
def find_bmi():
global bmi
bmi = 0
height = height_var.get()
weight = weight_var.get()
height = float(height) / 100.0
bmi = float(weight) / height ** 2
print("BMI = %0.2f" % bmi)
bmi = 0
main = mainwindow()
height_var = StringVar()
height_var.set("1")
weight_var = StringVar()
weight_var.set("1")
frame_1, frame_2, frame_3, frame_bottom = createframe(main)
ent_height, ent_weight = widget(frame_1, frame_2, frame_3, frame_bottom)
find_bmi()
main.mainloop()
I try to set a new value and calculate it because StringVar() can't calculate itself but when I use it that way I have to set the default to 1 if I don't set it will error ZeroDivisionError: float division by zero I don't want to set a number first if I set the first user will see that number
the frame_3 is used to show BMI to the user when calculating completed
You can check to see if the height and weight inputs have been filled in before doing the conversion/calculation.
from tkinter import *
def mainwindow():
main = Tk()
main.geometry("300x400")
main.title("BMI")
main.rowconfigure((0,1,2,3,4), weight=1)
main.columnconfigure(0, weight=1)
main.config(bg="green")
main.option_add("*Font", "times 15 bold")
return main
def createframe(main):
Label(main, text="BMI APP", bg="lightgreen").grid(row=0, column=0, sticky=N)
frame_1 = Frame(main, bg="white")
frame_1.grid(row=1, column=0, sticky="NEWS", padx=10, pady=10, ipady=5)
frame_2 = Frame(main, bg="white")
frame_2.grid(row=2, column=0, sticky="NEWS", padx=10, pady=10, ipady=5)
frame_3 = Frame(main, bg="white")
frame_3.grid(row=3, column=0, sticky="NEWS", padx=10, pady=10, ipady=20)
frame_bottom = Frame(main, bg="white")
frame_bottom.grid(row=4, column=0, sticky="NEWS", padx=10, pady=10, ipady=20)
frame_bottom.columnconfigure(0, weight=0)
frame_bottom.columnconfigure(1, weight=2)
return frame_1, frame_2, frame_3, frame_bottom
def widget(frame_1, frame_2, frame_3, frame_bottom):
Label(frame_1, text="HEIGHT:(cm.)").grid(row=0, column=0, padx=5, pady=5, sticky=W)
ent_height = Entry(frame_1, bg="pink", textvariable=height_var)
ent_height.grid(row=1, column=0, ipadx=40, padx=10, sticky=N+W)
Label(frame_2, text="WEIGHT:(kg.)").grid(row=0, column=0, padx=5, pady=5, sticky=W)
ent_weight = Entry(frame_2, bg="lightblue", textvariable=weight_var)
ent_weight.grid(row=1, column=0, ipadx=40, padx=10, sticky=N+W)
Label(frame_3, text="BMI").grid(row=0, column=0, padx=5, pady=5,sticky=W)
show_data = Label(frame_3)
show_data.grid(row=1, column=0, ipadx=40, padx=10, sticky=N+W)
Button(frame_bottom, text="Calculate", highlightbackground="lightgreen", fg="white", command=find_bmi).grid(row=2, column=1)
return ent_height, ent_weight, show_data
def find_bmi():
height = height_var.get()
weight = weight_var.get()
# check height and weight filled in
if height and weight:
height = float(height) / 100.0
bmi = round(float(weight) / height ** 2, 2)
show_data.config(text = bmi)
else:
show_data.config(text='')
main = mainwindow()
height_var = StringVar()
weight_var = StringVar()
frame_1, frame_2, frame_3, frame_bottom = createframe(main)
ent_height, ent_weight, show_data = widget(frame_1, frame_2, frame_3, frame_bottom)
main.mainloop()
I'm pretty new to Python. I can MAKE things work, but I'm never really sure if I'm actually using best practices, so forgive me if I'm not explaining things correctly, or if my code isn't written using best practices. I'm working on it!
I'm trying to figure out how to use tkinter's widget.config() to modify separate widgets that were created by the same method? For example, in the code below, how can I use widget.config() to modify the text in results section 2, r2??
from tkinter import *
from tkinter.ttk import *
class App():
def __init__(self, master):
self.master = master
self.master.title('Question')
self.create_main_frame()
def create_main_frame(self):
self.main_f = Frame(self.master)
nb = Notebook(padding=5)
nb.pack(anchor='w')
self.tab1(nb)
def tab1(self, nb):
tab1_frame = Frame(nb)
nb.add(tab1_frame, text='Tab 1', underline=0)
prod_lab = Label(tab1_frame, text='Entry:')
prod_lab.grid(row=1, column=0, padx=(10,0), pady=(10,5), sticky='e')
self.product_e = Entry(tab1_frame, width=40)
self.product_e.grid(row=1, column=1, padx=(0,10), pady=(10,5))
self.button1 = Button(tab1_frame,
text="Run",
command=self.run1
)
self.button1.grid(row=2, column=1, padx=(0,10), pady=(0,10), sticky='ne')
self.results1 = self.create_result(tab1_frame, 'Results Section 1')
self.results2 = self.create_result(tab1_frame, 'Results Section 2')
self.results3 = self.create_result(tab1_frame, 'Results Section 3')
def create_result(self, frame, name):
lab_frame = LabelFrame(master=frame, text=name)
lab_frame.grid(sticky='we', padx=10, pady=10, columnspan=10)
l1 = Label(master=lab_frame, text='Result 1:')
l1.grid(sticky='e', row=0, column=0, pady=2)
l2 = Label(master=lab_frame, text='Result 2:')
l2.grid(sticky='e', row=1, column=0, pady=2)
l3 = Label(master=lab_frame, text='Result 3:')
l3.grid(sticky='e', row=2, column=0, pady=2)
r1 = Label(master=lab_frame, text='')
r1.grid(sticky='w', row=0, column=1, pady=2)
r2 = Label(master=lab_frame, text='')
r2.grid(sticky='w', row=1, column=1, pady=2)
r3 = Label(master=lab_frame, text='')
r3.grid(sticky='w', row=2, column=1, pady=2)
def run1(self):
#This is the method that will be used to find the results I need
#For the sake of this question, let's pretend I want to put whatever text is in Entry 1, into results section 2 result 2
print (self.product_e.get())
print ('How do I use "widget.config()" to modify the 3 results sections separately???')
master = Tk()
app = App(master)
master.mainloop()
Thanks so much in advance for your help!
I'm not good in Tkinter so I would change create_result() to class Results.
from Tkinter import *
from ttk import *
class Results():
def __init__(self, frame, name):
self.lab_frame = LabelFrame(master=frame, text=name)
self.lab_frame.grid(sticky='we', padx=10, pady=10, columnspan=10)
self.l1 = Label(master=self.lab_frame, text='Result 1:')
self.l1.grid(sticky='e', row=0, column=0, pady=2)
self.l2 = Label(master=self.lab_frame, text='Result 2:')
self.l2.grid(sticky='e', row=1, column=0, pady=2)
self.l3 = Label(master=self.lab_frame, text='Result 3:')
self.l3.grid(sticky='e', row=2, column=0, pady=2)
self.r1 = Label(master=self.lab_frame, text='')
self.r1.grid(sticky='w', row=0, column=1, pady=2)
self.r2 = Label(master=self.lab_frame, text='')
self.r2.grid(sticky='w', row=1, column=1, pady=2)
self.r3 = Label(master=self.lab_frame, text='')
self.r3.grid(sticky='w', row=2, column=1, pady=2)
class App():
def __init__(self, master):
self.master = master
self.master.title('Question')
self.create_main_frame()
def create_main_frame(self):
self.main_f = Frame(self.master)
nb = Notebook(padding=5)
nb.pack(anchor='w')
self.tab1(nb)
def tab1(self, nb):
tab1_frame = Frame(nb)
nb.add(tab1_frame, text='Tab 1', underline=0)
prod_lab = Label(tab1_frame, text='Entry:')
prod_lab.grid(row=1, column=0, padx=(10,0), pady=(10,5), sticky='e')
self.product_e = Entry(tab1_frame, width=40)
self.product_e.grid(row=1, column=1, padx=(0,10), pady=(10,5))
self.button1 = Button(tab1_frame,
text="Run",
command=self.run1
)
self.button1.grid(row=2, column=1, padx=(0,10), pady=(0,10), sticky='ne')
self.results1 = Results(tab1_frame, 'Results Section 1')
self.results2 = Results(tab1_frame, 'Results Section 2')
self.results3 = Results(tab1_frame, 'Results Section 3')
def run1(self):
#This is the method that will be used to find the results I need
#For the sake of this question, let's pretend I want to put whatever text is in Entry 1, into results section 2 result 2
print (self.product_e.get())
print ('How do I use "widget.config()" to modify the 3 results sections separately???')
self.results1.r2.config(text='1111111111')
self.results2.r2.config(text='xxxxxxxxxx')
self.results3.r2.config(text='----------')
master = Tk()
app = App(master)
master.mainloop()