I'm new to tkinter and I've seen many lines of codes about switching frames using Tkinter Buttons, however but not Comboboxes. But upon clicking on the selected Combobox, it doesn't change to the respective frame, and is just being stuck on the start page.
I chose to begin with the Combobox to switch between different conversion modes (I'm working on a unit conversion calculator) and I find Comboboxes are the most practical option.
I started exactly how most people do their Comboboxes, but I haven't seen an example on how you would do it with Comboboxes. I tried the same thing using buttons and it worked for me. So looking for some help with this one, thanks!
import tkinter as tk
from tkinter import ttk
class main(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.resizable(height=1000, width=700)
self.title("a")
root = tk.Frame(self)
root.pack(fill="both", expand=True)
self.frames = {}
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (main_menuHauptmenu, lange):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(main_menuHauptmenu)
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class main_menuHauptmenu(ttk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
hm_label = ttk.Label(self, text="Wähle einen Masseneinheit", font=("Verdana", 15))
hm_label.pack()
mode = tk.StringVar()
unit_modus = ttk.Combobox(self, textvariable=mode)
unit_modus['values'] = ('Längenmasse')
unit_modus['state'] = 'readonly'
if unit_modus.get() == "Längenmasse":
lambda:controller.show_frame(lange)
unit_modus.pack()
#test_button = tk.Button(self, text="Lange", command=lambda:controller.show_frame(lange))
#test_button.pack()
# andere Masseneinheiten ...
class lange(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#for i in self.master.winfo_children():
# i.destroy()
gl_frame = tk.Frame(self)
gl_frame.pack()
of = tk.Frame(gl_frame)
of.pack(side='left')
pf = tk.Frame(gl_frame)
pf.pack(side='left')
rf = tk.Frame(gl_frame)
rf.pack(side='right')
qf = tk.Frame(gl_frame)
qf.pack(side='right')
## Label
Masseneinheit1 = tk.Label(of, text="Masseneinheit 1:").pack(side='top', anchor='nw')
Masseneinheit2 = tk.Label(of, text="Masseneinheit 2:").pack(side='top', anchor='nw')
## Entry
def validate_entry(text):
if (
all(char in "0123456789.-" for char in text) and
"-" not in text[1:] and
text.count(".") <= 1):
return True
else:
return False
nz = tk.StringVar()
ez = tk.Entry(pf, textvariable=nz, validate='key')
ez['validatecommand'] = (ez.register(validate_entry), '%P')
ez.pack(side='top')
resl = tk.StringVar()
res = tk.Label(pf, textvariable=resl)
res.pack(side='top')
## Combobox
enm = tk.StringVar()
em = ttk.Combobox(qf, textvariable=enm)
em['values'] = ('km', 'hm', 'dam', 'm', 'dm', 'cm', 'mm', 'in', 'ft', 'yd', 'mi')
em['state'] = 'readonly'
em.pack(side='top', anchor='ne')
em.current()
znm = tk.StringVar()
zm = ttk.Combobox(qf, textvariable=znm)
zm['values'] = ('mm', 'cm', 'dm', 'm', 'dam', 'hm', 'km', 'mi', 'yd', 'ft', 'in')
zm['state'] = 'readonly'
zm.pack(side='top', anchor='ne')
zm.current()
#Funktion
a = int()
km = 1000
hm = 100
dam = 10
m = 1
dm = 0.1
cm = 0.01
mm = 0.001
inch = 0.0254
ft = 0.3048
yd = 0.9144
mi = 1609.34
er = int()
zw = int()
combobox_er = str()
combobox_zw = str()
def conv():
# Zahl
er = km if em.get() == "km" else hm if em.get() == "hm" else m if em.get()\
== "m" else dam if em.get() == "dam" else \
dm if em.get() == "dm" else cm if em.get() == "cm" else \
mm if em.get() == "mm" else inch if em.get() == "in" else \
ft if em.get() == "ft" else yd if em.get() == "yd" else \
mi
zw = km if zm.get() == "km" else hm if zm.get() == "hm" else \
m if zm.get() == "m" else dam if zm.get() == "dam" else \
dm if zm.get() == "dm" else cm if zm.get() == "cm" else \
mm if zm.get() == "mm" else inch if zm.get() == "in" else \
ft if zm.get() == "ft" else yd if zm.get() == "yd" else \
mi
# Combobox
combobox_er = "km" if em.get() == "km" else "hm" if em.get() == "hm" \
else "dam" if em.get() == "dam" else "m" if em.get() == "m" else \
"dm" if em.get() == "dm" else "cm" if em.get() == "cm" else \
"mm" if em.get() == "mm" else "in" if em.get() == "in" else \
"ft" if em.get() == "ft" else "yd" if em.get() == "yd" else \
"mi"
combobox_zw = "km" if zm.get() == "km" else "hm" if zm.get() == "hm" else \
"dam" if zm.get() == "dam" else "m" if zm.get() == "m" else \
"dm" if zm.get() == "dm" else "cm" if zm.get() == "cm" else \
"mm" if zm.get() == "mm" else "in" if zm.get() == "in" else \
"ft" if zm.get() == "ft" else "yd" if zm.get() == "yd" else \
"mi"
if em.get() == combobox_er and zm.get() == combobox_zw:
a = float(nz.get()) * er / zw
resl.set(format(a, '.16f').rstrip('0').rstrip('.'))
else:
pass
button = tk.Button(rf, text="Umrechnen!", command=conv)
button.pack(side='top', anchor='ne')
app = main()
app.mainloop()
Note that the following code block inside main_menuHauptmenu.__init__()
:
if unit_modus.get() == "Längenmasse":
lambda:controller.show_frame(lange)
will be executed after creating the combobox, not when the selection of the combobox is changed. Also lambda:controller.show_frame(lange)
just defines a lambda
and does not execute it actually.
You need to bind the virtual event <<ComboboxSelected>>
on the combobox to a callback. Then the callback will be execcuted whenever there is selection change on the combobox:
unit_modus.bind("<<ComboboxSelected>>", lambda e:
controller.show_frame(lange) if unit_modus.get() == "Längenmasse" else None)
I would suggest to use a class method instead of lambda:
class main_menuHauptmenu(ttk.Frame):
def __init__(self, parent, controller):
...
self.controller = controller
...
unit_modus.bind("<<ComboboxSelected>>", self.on_combobox_selected)
...
def on_combobox_selected(self, event):
if event.widget.get() == "Längenmasse":
self.controller.show_frame(lange)