Skip to content Skip to sidebar Skip to footer

Tkinter Treeview Row Display Value Discrepancy With Underscore

I have a treeview display of invoice related data. The invoice identifiers have underscores. I have noticed the underscore displays correctly in the GUI however the invoice number

Solution 1:

tl;dr: Instead of doing item(row_selected)['values'], do item(row_selected, option='values').


I think this is actually a bug in tkinter, and the workaround is actually relying on another bug, so I filed both as b.p.o. #34447. But let's see what the tkinter experts over there say.


Meanwhile, you hopefully want to understand why that makes a difference, right?

If you look at the docs for item:

Query or modify the options for the specified item.

If no options are given, a dict with options/values for the item is returned. If option is specified then the value for that option is returned. Otherwise, sets the options to the corresponding values as given by kw.

So, if you ask for the values option, you get the values option's value.

But if you don't ask for anything, tkinter tries to get clever and give you a dict with all of the options.

The problem is that, under the covers, tkinter is a wrapper around Tcl/Tk. In Tcl, everything is a string (it's more like, say, bash in this regard than Python); there's no difference between the number 123 and the string '123'. It's perfectly legal to store ints in TreeView items, but they get stored exactly the same way as strings.

And what's returned by the Tcl code to get all of the options for an item is a Tcl list of Tcl key-value pairs where all of the values are Tcl strings. Tkinter has no idea which ones were supposed to be strings, and which were supposed to be ints. So it tries to guess: any string that can be converted to an int with the int constructor is an int, anything else is a string. And your string can be converted to an int, so it is.

Of course this is pretty hacky, but it usually does what you want, and it makes things more convenient when it does, and "pretty hacky but usually does what you want conveniently" is almost the definition of tkinter.

However, I think it ought to recognize that, while '123_456' is a perfectly valid Python integer literal, it's not a string that could ever be created by Tcl for an integer, so it shouldn't try to parse that.

If you want to see the code that does this: ttk.TreeView.item calls ttk._val_or_dict, which calls tkinter._splitdict with ttk._tclobj_to_py as a value-converter.


But why doesn't _val_or_dict run the converter over a single key-value pair? I can't honestly see a good reason for this. But it doesn't, so we can take advantage of that fact to work around the problem.


1. What if a value was supposed to be a float? Well, that doesn't come up very often in TreeViews, so tkinter doesn't bother with that one; you just get the string representation of your float. But in other types, like LabeledScale, where floats are more useful/common, it uses a different function that tries float instead of int if there' a . in the string.

2. If you're curious what this looks like, even after the Tcl list has been parsed, try printing the results of tree.tk.call(tree._w, 'item', row_selected) vs. tree.tk.call(tree._w, 'item', row_selected, '-values').

3. In earlier versions of Python, 180618_24 wasn't a valid int literal, so you'd still get a string. But in 3.6, underscores are allowed as group separators, so 180618_24 is a perfectly valid way to spell 18061824, so that's what you get.

Post a Comment for "Tkinter Treeview Row Display Value Discrepancy With Underscore"