当我仅使用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
放在函数中可以正常工作。如果有人能解释这一点,我将不胜感激
答案 0 :(得分: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
。通过将所有单选按钮链接到相同的变量来对其进行“分组”。由于单选按钮具有变量,因此单击它们之一时,该变量将设置为按钮的值。接下来,添加与tkinter OptionMenu中相同的命令。如前所述,这将设置变量,然后触发另一个提供的命令。如您所见,现在变量被更新两次,一次是因为它链接到单选按钮,另一次是因为它是在_setit
函数中设置的。因为您跟踪变量的更改并且变量设置了两次,所以您的代码也运行两次。
因为该变量在ttk代码中设置了两次,所以我想您对此无能为力。如果您不更改代码的其他部分而不是OptionMenu的变量,则可以选择不跟踪变量,而是将函数command
添加到OptionMenu:
entry1 = ttk.OptionMenu(root, first, *Ore.keys(), command=_up_options)
P.S。在this commit之后由this bugreport引入。
我猜想在添加variable=self._variable
时,该命令应该已经更改为command=self._callback
。
答案 1 :(得分:2)
您可以通过错误消息了解问题所在:
Tkinter回调中的异常 追溯(最近一次通话): 调用中的文件“ C:\ Users \ user \ AppData \ Local \ Programs \ Python \ Python36 \ lib \ tkinter__init __。py”,行1699 返回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
。
希望这对您有所帮助!
答案 2 :(得分:0)
不是跟踪StringVar,而是为OptionMenu构造函数添加回调作为命令参数。