I have a tkinter application with variable number of entries and I want to detect changes to the contents and specifically, which entry has been changed
import tkinter as tk
from tkinter import ttk
DOGS = 3
def main() -> None:
root = tk.Tk()
root.title('')
root.geometry('400x400')
dogs = {}
entries = {}
for row in range(DOGS):
dogs[row] = tk.StringVar()
dogs[row].trace_add('write', dog_changed)
entries[row] = ttk.Entry(root, textvariable=dogs[row])
entries[row].grid(row=row, column=0)
root.mainloop()
def dog_changed(*args):
print(args)
if __name__ == '__main__':
main()
I can see in args that I have the name of the StringVar as a string (e.g."PY_VAR0"), but is there a more elegant way of getting a reference to which entry has been changed rather than taking a substr here.
I have tried this lambda function, but of course it only show the current value of row
dogs[row].trace_add('write', lambda *args: dog_changed(row, *args))
I'm not sure if this helps, but you can specify the name
of your StringVar
instances:
dogs[row] = tk.StringVar(name=f'dog{row}') # you can set this to whatever you likez
Which prints this:
('dog0', '', 'write')
('dog1', '', 'write')
('dog2', '', 'write')
You could also set an event binding on the Entry
widgets themselves, such as '<Key>'
which will fire whenever a key is pressed inside the widget. Then you can get the widget's reference from the passed event
(you probably don't even need the trace
binding if you do it this way):
# put this in your for loop
entries[row].bind('<Key>', lambda e: print(e.widget))
Note that you don't have to use a lambda
here - you could bind this to a function instead; that function just needs to accept the incoming event
parameter.