为什么从lambda更改变量不起作用?

时间:2017-11-14 01:12:28

标签: python python-3.x tkinter

我一直在研究Tkinter并且发现在不同帧之间传递值时遇到问题,因此我使用this tutorial here提供的“共享数据”解决方案跟随Bryan Oakley并将其添加到我自己的代码中。 除非我无法将“共享数据”字典中的值设置为按钮上的命令。

下面的代码中的一些注释概述了问题。如果我只是尝试在我的选择页面的init期间更改变量,它会正常更改。但是将它放在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()

2 个答案:

答案 0 :(得分:1)

在帧之间传递数据并不太难。有两种方法我喜欢这样做。

方法1:

设置一个类似于这样的框架....

class ThirdName(tk.Frame):   

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        self.controller = controller

现在只需说出:

self.data = "this is some data"

现在当你在另一个框架中时,你可以这样称呼它:

print(ThirdName.data)
>>> "this is some data"

第二种方式是将它发送到这样的地方:

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)

鲍比将获得数据:)

确定....第二点......在帧之间移动可以通过以下方式完成:

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)

**用这样的东西设置框架:

class SecondName(tk.Frame):   

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        self.controller = controller

是的,self.controller方法也是我使用的方法,在一帧中将大量数据放在一起很好。

答案 1 :(得分:0)

为什么使用'controller'代替'self.controller'?在构造函数的开头指定'self.controller'然后使用'controller'代替,这有点令人困惑。也许变量阴影会导致你的问题。