当ttk小部件被使用时,tkinter函数重复两次

问题描述 投票:3回答:3

当我只使用tkinter的小部件时,该程序按预期工作。当我使用ttk的小部件时,程序会重复两次。我尝试了几乎所有知识来解决这个问题,我相信*args与它有关。有什么方法可以阻止我的function跑两次吗?

from tkinter import *
from tkinter import ttk
root = Tk()

first = StringVar(root)
second = StringVar(root)
Ore = {'Options': [''], 'Yes': ['One'], 'No': ['Two']}
entry1 = ttk.OptionMenu(root, first, *Ore.keys())
entry2 = ttk.OptionMenu(root, second, '')
entry1.pack()
entry2.pack()


def _up_options(*args):
    print('update_options')
    ores = Ore[first.get()]
    second.set(ores[0])
    menu = entry2['menu']
    menu.delete(0, 'end')

    for line in ores:
        print('for')
        menu.add_command(label=line, command=lambda choice=line: second.set(choice))


first.trace('w', _up_options)

root.mainloop()

PS,我把*args放在我的功能中工作。如果有人能够解释这一点,我将非常感激

python-3.x tkinter ttk
3个回答
3
投票

我想我想出来了。问题是变量实际上是由ttk OptionMenu设置的两次。

看一下tkinter OptionMenu中的这段代码:

for v in values:
    menu.add_command(label=v, command=_setit(variable, v, callback))

这会使用_setit命令为每个值的菜单添加一个按钮。当调用_setit时,它设置变量和另一个回调(如果提供):

def __call__(self, *args):
    self.__var.set(self.__value)
    if self.__callback:
        self.__callback(self.__value, *args)

现在看一下ttk OptionMenu中的这段代码:

for val in values:
    menu.add_radiobutton(label=val,
        command=tkinter._setit(self._variable, val, self._callback),
        variable=self._variable)

而不是command这增加了radiobutton菜单。所有单选按钮都通过将它们链接到同一变量来“分组”。由于radiobuttons具有变量,因此当单击其中一个变量时,变量将设置为按钮的值。接下来,添加与tkinter OptionMenu中相同的命令。如上所述,这将设置变量,然后触发另一个提供的命令。正如您所看到的,现在变量被更新两次,一次是因为它与radiobutton相关联,因为它是在_setit函数中设置的。因为您跟踪变量的变化并且变量设置了两次,所以您的代码也会运行两次。

因为变量是在ttk代码中设置的两倍,所以我猜你可以做的不多。如果您不从代码的任何其他部分更改变量而不是从OptionMenu更改变量,您可以选择不跟踪变量,而是将您的函数作为command添加到OptionMenu:

entry1 = ttk.OptionMenu(root, first, *Ore.keys(), command=_up_options)

附:这是在this commit之后与this bugreport一起引入的。 我想当添加variable=self._variable时,命令应该已经改为command=self._callback


2
投票

您可以在错误消息中了解该问题:

Tkinter回调中的异常回溯(最近一次调用最后一次):文件“C:\ Users \ user \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ tkinter__init __。py”,第1699行,在调用return self.func(* args) )TypeError:_up_options()获取0个位置参数,但给出了3个

最初,您不使用_up_options更改选项时,调用_up_options来跟踪第一个StringVar并将其更改为字典中下一个对象的值。

现在,当你这样做时,你正在运行字典中的所有对象,因此,你需要*args所以lambda函数将在所有给定的args上运行!

至于你的问题:

当我使用ttk的小部件时,程序会重复两次。

编辑

看@ fhdrsdg的回答!

解决方案只是将command=tkinter._setit(self._variable, val, self._callback)改为command=self._callback

希望你觉得这很有帮助!


0
投票

而不是跟踪StringVar,为OptionMenu构造函数添加一个回调作为命令参数。

© www.soinside.com 2019 - 2024. All rights reserved.