【问题标题】:textvariable argument in tkinter not updating after initial run [duplicate]tkinter中的textvariable参数在初始运行后没有更新[重复]
【发布时间】:2019-04-13 16:12:51
【问题描述】:

我第一次使用tkinter 模块,我在创建标签/按钮时发现了textvariable 参数等等。 它只在第一次更新。我已经扭曲了检索命令的方法,但似乎没有任何效果。我撞到了一堵砖墙。

from tkinter import *

x = 1
y = 1
z = 0

class App:
    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        textVar = StringVar()
        self.button = Button(
            frame, textvariable=textVar, command=textVar.set(str(fibonacci()))
        )
        self.button.pack()

def fibonacci():
    global x, y, z
    z = x
    x = x + y
    y = z
    return x

root = Tk()
app = App(root)
root.mainloop()

【问题讨论】:

  • 关键字参数command 接受一个函数,而您传递的是函数的一个实例。定义一个更新textVar的函数,并将不带括号的函数赋值给command

标签: python class user-interface tkinter


【解决方案1】:

看看这个语句片段:

self.button = Button(..., command=textVar.set(str(fibonacci()))

在功能上等价于:

result = textVar.set(str(fibonacci()))
self.button = Button(..., command=result)

看到问题了吗?您正在调用textVar.set(...) 立即,并将其结果用作command 属性的值。 textVar.set(...) 返回None,所以你有效地做command=None

不要尝试将代码放入command 参数中。相反,创建一个适当的函数并将其设为 command 属性的值。这将使您的代码更易于理解、更易于维护和更易于调试。

例子:

def __init__(self, master):
    ...
    self.button = Button(..., command=self.do_something)
    ...

您遇到的第二个问题是您使用局部变量来存储StringVar() 的结果。这意味着一旦函数完成运行,它就会被垃圾收集器删除。

要解决此问题,请将属性分配给实例变量:

def __init(self, master):
    ...
    self.textVar = StringVar()
    self.button = Button(..., command=self.do_something)
    ...

def do_something()
    self.textVar.set(str(fibonacci()))

【讨论】:

  • command=self.update()command=self.update 之间似乎存在巨大差异...这是函数引用和尝试调用它之间的区别吗?我不确定如何正确表达它。
  • @Xevion:是的,这就是区别。虽然,self.update() 并没有尝试调用它,它实际上调用了它。
【解决方案2】:

您的代码存在几个问题。首先,您需要将textVar 设为实例属性,以便即使在__init__() 方法返回后它仍然存在。在您的代码中,它是一个局部变量,当它返回时会消失。

其次,Buttoncommand 选项应设置为稍后单击时调用的函数,但您的代码在创建小部件本身时调用它一次。您可以通过使用lambda 表达式来定义一个“匿名”函数来解决此问题,该函数会在被调用时调用所需的函数。

x = 1
y = 1
z = 0

class App:
    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        self.textVar = StringVar()  # Make an instance attribute.
        self.textVar.set(x)  # Set to show initial value of x.
        self.button = Button(frame, textvariable=self.textVar,
                             command=lambda: self.textVar.set(fibonacci()))
        self.button.pack()


def fibonacci():
    global x, y, z
    z = x
    x = x + y
    y = z
    return x

root = Tk()
app = App(root)
root.mainloop()

可以在不使用lambda 的情况下执行相同的操作,如下面的代码所示。 注意 command=self.button_click_callback 的使用只是指定了函数的名称,但实际上并没有像使用 command=self.button_click_callback() 那样调用它。此外,由于 button_click_callback 被定义为类方法,它会自动获取传递给的 self 参数(与通过 lamba 表达式内联定义的函数不同)。

无论如何,如您所见,以这种方式做事需要多几行代码。

from tkinter import *

x = 1
y = 1
z = 0

class App:
    def __init__(self, master):
        frame = Frame(master)
        frame.pack()

        self.textVar = StringVar()  # Define as a instance attribute.
        self.textVar.set(x)  # Set to show initial value of x.
        self.button = Button(frame, textvariable=self.textVar,
                             command=self.button_click_callback)
        self.button.pack()

    def button_click_callback(self):
        """ Called whenever button is clicked. """
        self.textVar.set(fibonacci())

def fibonacci():
    global x, y, z
    z = x
    x = x + y
    y = z
    return x

root = Tk()
app = App(root)
root.mainloop()

【讨论】:

  • 我对 Python 中的 Lambda 不是很了解。我在 Java 中做了一堆练习题,但我无法弄清楚在前面输入 lambda: 是如何完全改变我的问题的。另外,是的,我确实了解局部变量/垃圾收集的工作原理。我会记住这一点的。
  • @Xevion: 使用lambda 通常对编写tkinter 程序很有用,所以我建议继续尝试理解这个概念,它基本上允许您创建返回结果的简短的通常单行函数评估它们包含的表达式,而不必使用通常的def myfunction(): 多语句格式编写一个。但是,不需要使用它们。无论如何,如果我的回答解决了您的问题,请考虑接受。见What should I do when someone answers my question?
【解决方案3】:

我个人放弃了在具有 anaconda 环境(使用 Spyder)的 Windows PC 上的 textvariable:我有太多的级别和嵌套,并且任何地方都丢失了东西。特别是由于命令和 lambda 使用的“回调”情况。看起来其他人也对 textvariable 感到困惑(建议不要使用它..Tkinter Entry not showing the current value of textvariable) 像你一样,我在 init 部分中使用了用 .set('is it there?') 初始化的 textvariable,稍后在条目中重新使用,不显示文本'is it there'。抱歉没有明确的解决方案,但看起来没有这个文本变量的生活可以继续。

到目前为止我能找到的最好的摘要链接是How to pass arguments to a Button command in Tkinter?。一切都在那里:解释了 lambda,稍微解释了回调,由于回调情况,被调用函数中的文本变量没有更新,使用全局变量来更改参数等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-10
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-26
    相关资源
    最近更新 更多