I seem to misunderstand how trace works for tkinter.StringVar
.
I want to create a class that inherits from StringVar
. One of the reasons is to have a different behavior if the value is changed "programmatically" i.e. using StringVar.set()
, or "via interface", i.e. by user modifying a linked tkinter.Entry
.
In general, I want something of the following sort:
import tkinter
class Str(tkinter.StringVar):
def __init__(self, value):
super().__init__(value=value)
self.trace_add("write", self.entry_changed)
def set(self, new_value):
# Do things
super().set(new_value)
def entry_changed(self, *args):
new_value = super().get()
# Do things
super().set(new_value)
since I was hoping that StringVar.set
does not trigger trace - unfortunately it does. Now, I have in mind a workaround with a bool flag that would skip entry_changed
one time after changing the value "programmatically", but then I realized I clearly don't understand something about how trace triggers.
Q. Why does the super().set(new_value)
in Str.entry_changed
does not trigger trace?
Since super().set()
triggers trace in Str.set
, I'd expect it to also trigger in entry_changed
, creating an endless loop.
Below is an example. entry_changed
additionally changes the new_value
just to make sure that trace isn't triggered because the value remains the same:
import tkinter
class Str(tkinter.StringVar):
def __init__(self, value):
super().__init__(value=value)
self.trace_add("write", self.entry_changed)
def set(self, new_value):
print("Set value")
super().set(new_value)
def entry_changed(self, *args):
print("Entry changed")
new_value = super().get()
super().set(new_value + "_")
root = tkinter.Tk()
var = Str("0")
var.set("a")
print(var.get())
outputs:
Set value
Entry changed
a_