【发布时间】:2017-11-14 18:24:54
【问题描述】:
我一直在研究 Tkinter,发现在不同帧之间传递值时遇到问题,所以我关注了this tutorial here,使用Bryan Oakley 提供的“共享数据”解决方案并将其添加到我自己的代码中。 除了我不能将“共享数据”字典中的值设置为按钮上的命令。
下面代码中的一些 cmets 概述了问题。如果我只是在选择页面的初始化期间尝试更改变量,它会正常更改。但是把它放在一个 lambda 中意味着字典变量根本不会改变。并且尝试为按钮命令使用 def 有其自身的复杂性。
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()
【问题讨论】:
-
你不应该使用
lambda来做除了调用单个函数之外的任何事情。如果您需要做更多的事情,请创建一个适当的函数或方法。这将更容易阅读,也更容易调试。 -
这是因为您在发生任何更改之前初始化了
ValuePage的实例(在初始化RegApp时),因此存在您的问题。使事情更加动态 - 当您在ValuePage(title_label = ttk.Label(self, textvariable=self.controller.shared_data["choice"], font=SUBTITLE_FONT, justify=tk.CENTER)) 中创建Label时,使用textvariable而不是text。此外,两个函数调用的列表理解是一种廉价的黑客攻击! -
您知道您需要传递 lambda 调用需要首先传递给 lambda 的函数的参数,就像在
command=lambda var=num: self.button_command(var)中一样,对吧?
标签: python python-3.x tkinter