Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

tkinter function repeats itself twice when ttk widgets are engaged

The program works as intended when I simply use tkinter's widgets. When I use ttk's widgets the program repeats itself twice. I tried almost everything in my knowledge to fix this, I believe that *args have something to do with it. Is there anyway to prevent my function _up_options from running twice?

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, I used *args in my function to work. If anyone can explain this, I would be very grateful

like image 858
Magotte Avatar asked Jan 01 '23 15:01

Magotte


1 Answers

I think I figured this out. The problem is that the variable actually is set twice by the ttk OptionMenu.

Take a look at this piece of code from the tkinter OptionMenu:

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

This adds a button to the menu for each value, with a _setit command. When the _setit is called it sets the variable and another callback if provided:

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

Now look at this piece of code from the ttk OptionMenu:

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

Instead of a command this adds a radiobutton to the menu. All radiobuttons are "grouped" by linking them to the same variable. Because the radiobuttons have a variable, when one of them is clicked, the variable is set to the value of the button. Next to this, the same command is added as in the tkinter OptionMenu. As said, this sets the variable and then fires another command of provided. As you can see, now the variable is updated twice, once because it is linked to the radiobutton and once more because it is set in the _setit function. Because you trace the changing of the variable and the variable is set twice, your code also runs twice.

Because the variable is set twice from within the ttk code, I guess there's not much you can do about that. If you don't change the variable from any other part of your code than from the OptionMenu though, you could choose to not trace the variable, but instead add your function as command to the OptionMenu:

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

P.S. this was introduced with this commit after this bugreport.
I guess when adding the variable=self._variable the command should have been changed to just command=self._callback.

like image 108
fhdrsdg Avatar answered May 12 '23 18:05

fhdrsdg