【问题标题】:How can I access the particular tkinter StringVar that triggers a trace callback?如何访问触发跟踪回调的特定 tkinter StringVar?
【发布时间】:2018-02-14 01:09:30
【问题描述】:

我正在尝试使用跟踪回调来验证对一组组合框的输入,但我在回调中获得的参数只是内部名称的字符串表示形式。有没有办法获取对触发跟踪回调的实际变量的引用,或者使用 PY_VAR1 等内部名称获取变量的方法?

from Tkinter import *
import ttk


def validate(self, *args):
    print(self)
    print(self.get())

master = Tk()

cb1_var = StringVar()
cb2_var = StringVar()
cb1_var.trace('w', validate)
cb2_var.trace('w', validate)

cb1 = ttk.Combobox(master, textvariable=cb1_var)
cb2 = ttk.Combobox(master, textvariable=cb2_var)

cb1.grid(row=0, column=0, sticky='NW')
cb2.grid(row=1, column=0, sticky='NW')

mainloop()

尝试调用 self.get() 失败,因为 self 只是那个字符串表示,而不是实际的 StringVar。我不想为每个 StringVar 设置一个特定的回调,因为实际的界面有大约 30 个框,我都希望通过相同的标准进行验证。

【问题讨论】:

  • 如果您有大约 30 个组合框和文本变量,为什么不使用集合类型?
  • 问之前有没有研究过?我觉得我在过去一两周内回答了类似的问题。
  • 是的。对不起,我没有找到你的答案。我遇到了一篇文章,解释了提供给 trace 的参数“是内部变量名。在 tkinter 上下文中或多或少没用,但对底层 tcl 解释器非常有用。”但似乎我应该能够使用它来获取实际的 StringVar,这就是我问的原因。

标签: python tkinter


【解决方案1】:

您可以通过使用匿名函数的lambda 语句来简单地传递您想要的参数。替换:

def validate(self, *args):
    print(self)
    print(self.get())

...

cb1_var.trace('w', validate)
cb2_var.trace('w', validate)

与:

def validate(var):
    print(var)
    print(var.get())

...

cb1_var.trace('w', lambda *_, var=cb1_var: validate(var))
cb2_var.trace('w', lambda *_, var=cb2_var: validate(var))

如果您使用多个相关的对象,只需使用集合类型。对于问题中的示例,我认为 list 应该很合适。

请看下面的例子:

try:                        # In order to be able to import tkinter for
    import tkinter as tk    # either in python 2 or in python 3
    import tkinter.ttk as ttk
except ImportError:
    import Tkinter as tk
    import ttk


def upon_var_change(var):
    print(var.get())


if __name__ == '__main__':
    root = tk.Tk()
    cbs = list()
    for i in range(3):
        cbs.append(ttk.Combobox(root))
        cbs[i].var = tk.StringVar()
        cbs[i].var.trace_add('write', lambda *_,
                                        var=cbs[i].var:upon_var_change(var))
        cbs[i]['textvariable'] = cbs[i].var
        cbs[i].grid(row=i // 2, column=i % 2, sticky='nw')
    tk.mainloop()

如果需要,您也可以从其内部引用中识别变量类:

try:                        # In order to be able to import tkinter for
    import tkinter as tk    # either in python 2 or in python 3
    import tkinter.ttk as ttk
except ImportError:
    import Tkinter as tk
    import ttk


def upon_var_change(var_name):
    value = root.tk.globalgetvar(var_name)
    print(var_name, value)


if __name__ == '__main__':
    root = tk.Tk()
    cbs = list()
    for i in range(3):
        cbs.append(ttk.Combobox(root))
        cbs[i].var = tk.StringVar()
        cbs[i].var.trace_add('write', lambda var_name,
                                                *_: upon_var_change(var_name))
        cbs[i]['textvariable'] = cbs[i].var
        cbs[i].grid(row=i // 2, column=i % 2, sticky='nw')
    tk.mainloop()

【讨论】:

  • 我在 var=cbs[i].var 分配中遇到无效的语法错误。不过,我会尝试摆弄 lambda 函数,这似乎是要走的路。我正在使用 Python 2.7,以防出现 2 对 3 的语法问题。
  • @pwpropipe 到底是什么错误?声明 var 的顺序很重要。
  • File "test.py", line 19 cbs[i].var.trace_add('write', lambda *_, var=cbs[i].var:upon_var_change(var)) ^ SyntaxError: invalid syntax ^ 指向 var=csb[i] 中的 r
  • @pwpropipe 我会检查上面和下面的行,因为它对我有用。
  • 你应该得到一个士力架吧!谢谢好心的先生!
【解决方案2】:

我知道这是一篇旧帖子,我找到了一种使用内部变量名的方法。像这样修改你的 validate 函数:

def validate(self, *args):
    var_name = args[0]
    var = IntVar(name=var_name)
    print(var.get())

master = Tk()

cb1_var = StringVar()
cb2_var = StringVar()
cb1_var.trace('w', validate)
cb2_var.trace('w', validate)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-07
    • 2014-10-11
    相关资源
    最近更新 更多