私はTkinterに取り組んでいて、異なるフレーム間で値を渡すのが難しいので、Bryan Oakleyで提供される "共有データ"ソリューションを使用して自分のコードに追加してthis tutorial hereに従った。 「共有データ」辞書の値をボタンのコマンドとして設定することはできません。ラムダからの変数の変更が機能しないのはなぜですか?
以下のコードのコメントは、この問題の概要を示しています。選択したページの初期化中に変数を変更しようとすると、それは正常に変更されます。しかし、それをラムダに入れることは、辞書変数がまったく変更されないことを意味します。また、ボタンコマンドに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'を使うべきではありません。それ以上のことをする必要がある場合は、適切な関数またはメソッドを作成します。これは読みやすく、デバッグも簡単です。 –
これは、(RegAppの初期化時に)変更が発生する前に 'ValuePage'のインスタンスを初期化しているためです。そのため、問題があります。 'ValuePage'で' Label'を作成するときに、 'text'の代わりに' textvariable'を使用します。 'title_label = ttk.Label(self、textvariable = self.controller.shared_data [" choice "]、font = SUBTITLE_FONT、justify = tk.CENTER) ')。また、2つの関数呼び出しのリストの理解は安いハックです! – CommonSense
あなたはラムダコールがlambdaに渡す必要がある関数の引数を 'command = lambda var = num:self.button_command(var)'のようにまず渡す必要があることを認識していますか? – Nae