Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to get a reference to traced variable in tkinter

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    dogs[row].trace_add('write', lambda *args: dog_changed(row, *args))

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading