25

Python has classes for Tkinter variables StringVar(), BooleanVar(), etc. These all share the methods get(), set(string), and trace(mode, callback). The callback function passed as the second argument to trace(mode, callback) is passed four arguments, self, n, m, x.

For an example of a BooleanVar() these appear to be '', 'PYVAR0', 'w'.

The third argument x appears to be the mode that triggered the trace, in my case the variable was changed. However, what is the first variable that appears to be an empty string? What is the second, if I had to guess I'd say some internal name for the variable?

Marshall Davis
  • 3,337
  • 5
  • 39
  • 47

2 Answers2

38

The first argument is the internal variable name. You can use this name as an argument to the tkinter getvar and setvar methods. If you give your variable a name (eg: StringVar(name='foo')) this will be the given name, otherwise it will be a name generated for you by tkinter (eg: PYVAR0)

If the first argument represents a list variable (highly unlikely in tkinter), the second argument will be an index into that list. If it is a scalar variable, the second argument will be the empty string.

The third argument is the operation, useful if you are using the same method for reading, writing and/or deleting the variable. This argument tells you which operation triggered the callback. It will be one of "read", "write", or "unset".

Tkinter is a python wrapper around a tcl/tk interpreter. The definitive documentation for variable traces can be found here: http://tcl.tk/man/tcl8.5/TclCmd/trace.htm#M14. Though, this only documents how the internal trace works, the tkinter wrapper sometimes massages the data.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • 3
    The first argument is super-useful if the trace callback is a method in a class instance. In this case, the first argument points to the class instance. There may well be other circumstances where the "scope" of the callback causes the first argument to be very useful. – GaryMBloom Nov 11 '17 at 04:30
  • 2
    I forgot to mention that if you give your variable a name when you create it (using the 'name' keyword), that name gets passed in as the first arg to the callback instead of the not-so-helpful generic tkinter name. This allows you to share callback functions across multiple variables more easily if you want. And. if you're motivated, you can use that name for direct access to the variable, perhaps by having stored the variable in a dict, although I'm not sure that would give you anything but trouble. – GaryMBloom Nov 04 '19 at 00:06
  • 1
    The first argument it is not useless. See @Keith Caufield answer below. You can assign the name of the variable (first argument) to a variable which you can then use for example the get the value with get() method. For example temp_var = IntVar(name=args[0]) and then you can do temp_var .get(). Whenever you have time update the answer, please. Thanks – Francesco Apr 29 '20 at 09:48
  • @Francesco: I've updated my answer. Thanks for the comment. – Bryan Oakley Apr 29 '20 at 14:59
14

The first argument is the name of the variable, but is not "useless" since you can set it when you declare the variable, e.g.:

someVar = IntVar(name="Name of someVar")

When you check the first argument in the trace callback it will equal "Name of someVar". Using the name to distinguish between variables, you can then bind the same handler to trace changes to any number of variables, rather than needing a separate handler for each variable.

Paul Roub
  • 36,322
  • 27
  • 84
  • 93
Keith Caulfield
  • 157
  • 1
  • 3
  • I had no idea you could name them. Thanks. – Andrew H Mar 14 '18 at 00:17
  • 3
    While providing useful information, by itself this isn't an answer to the OP's question. The appropriate place for it would be as a comment under @Bryan Oakley's answer. – martineau Apr 03 '18 at 17:56
  • 2
    This answer would be much more useful if it included the tkinter function that lets me retrieve the variable by name. The `nametowidget()` member functions only seems to know about widget (as implied by its name). – josch Jun 12 '19 at 21:21
  • Man, this answer should be added to the accepted answer!!! It was exactly what I was looking for, but it took me 10 minutes to find it only because the main answer said that the first argument is useless. It is absolutely the opposite of useless. With the possibility to use that variable name you can have a list of StringVar and then when one of them is changed you can know which one changed in the list! Thank you very much! – Francesco Apr 29 '20 at 09:46
  • Can you provide an example of the syntax in your answer for your statement _"you can then bind the same handler to trace changes to any number of variables, rather than needing a separate handler for each variable."_ ? – Sun Bear Nov 11 '21 at 17:56