Reputation: 73
I have been working on Tkinter and am finding trouble passing values between different frames, so I followed this tutorial here, using the "shared data" solution provided by Bryan Oakley and adding it to my own code. Except I cannot set the value in the "shared data" dictionary as a command on a button.
A few comments in the code below outline the problem. If I just try to change the variable during the init of my choice page, it changes normally. But putting it in a lambda means that the dictionary variable won't change at all. And trying to use a def for the button command has its own complications.
import tkinter as tk
import tkinter.ttk as ttk
# from tkinter import messagebox
TITLE_FONT = ("Segoe UI Light", 22)
SUBTITLE_FONT = ("Segoe UI Light", 12)
window_size = [300, 200]
resistors = []
choice = "default"
class RegApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default="test.ico")
tk.Tk.wm_title(self, "Test")
self.shared_data = {
"choice": tk.StringVar(),
}
container = tk.Frame(self, width=window_size[0], height=window_size[1])
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 panels:
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="NSEW")
self.show_frame(WelcomePage)
def show_frame(self, container):
frame = self.frames[container]
frame.tkraise()
class WelcomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
title_label = ttk.Label(self, text="Welcome", font=TITLE_FONT)
subtitle_label = ttk.Label(self, text="Let's run some numbers.", font=SUBTITLE_FONT)
start_button = ttk.Button(self, text="Begin", width=24, command=lambda: controller.show_frame(ChoicePage))
title_label.pack(pady=(40, 5))
subtitle_label.pack(pady=(0, 10))
start_button.pack()
class ChoicePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.controller.shared_data["choice"].set("test2") # Here, the variable is set fine
title_label = ttk.Label(self, text="Is your resistor network \nin series or parallel?", font=SUBTITLE_FONT,
justify=tk.CENTER)
series_button = ttk.Button(self, text="Series", width=24,
command=lambda: [self.controller.shared_data["choice"].set("series"), controller.show_frame(ValuePage)])
# But when I use it in a lambda, the variable doesn't even seem to set at all. It switches to the next page and has the value ""
parallel_button = ttk.Button(self, text="Parallel", width=24,
command=lambda: controller.show_frame(ValuePage))
title_label.pack()
series_button.pack()
parallel_button.pack()
# TODO Make the user select between 'series' and 'parallel'
class ValuePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
title_label = ttk.Label(self, text=self.controller.shared_data["choice"].get(), font=SUBTITLE_FONT,
justify=tk.CENTER)
title_label.pack()
panels = [WelcomePage, ChoicePage, ValuePage]
app = RegApp()
app.resizable(False, False)
app.geometry('{}x{}'.format(window_size[0], window_size[1]))
app.mainloop()
Upvotes: 0
Views: 92
Reputation: 192
well passing data between frames isn't too hard. there are 2 ways I like to do it.
Method 1:
class ThirdName(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
now just say something like:
self.data = "this is some data"
now when you're in another frame you can call it like this:
print(ThirdName.data)
>>> "this is some data"
Second way is just to send it somewhere like this:
value_1 = 'Richard'
bobby_def(value_1, 42, 'this is some text')
...
def bobby_def(name, number, text)
print(text)
or...
return(name, number, text)
Bobby will get the data :)
ok.... second point... moving between frames can be done with something like this:
self.button_to_go_to_home_page = tk.Button(self, text='Third\nPage', font=Roboto_Normal_Font,
command=lambda: self.controller.show_frame(ThirdName),
height=2, width=12, bd = 0, activeforeground=active_fg, activebackground=active_bg, highlightbackground=border_colour,
foreground=bg_text_colour, background=background_deselected)
self.button_to_go_to_home_page.place(x=20, y=280)
**set up a frame with stuff like this:
class SecondName(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
Yes, the self.controller method is one I use too and it's nice to have lots of your data together in one frame.
Upvotes: 1
Reputation: 156
Why are you using 'controller' instead of 'self.controller'? It's kind of confusing that you assign 'self.controller' at the start of the constructor and then you use 'controller' instead. Maybe that variable shadowing is causing your problem.
Upvotes: 0