[Python-Dev] ttk.Treeview.insert() does not allow to insert item with iid=0

810 views
Skip to first unread message

Игорь Яковченко

unread,
Mar 16, 2018, 1:26:07 PM3/16/18
to pytho...@python.org
Hello,

I found a possible bug with ttk.Treeview widget. 
I'm working on program that uses tkinter UI. I use ttk.Treeview to display some objects and I want to use integer iid of items.
For example, I insert a row with treeview.insert(... iid=0, ...). But I encountered a problem when I try to get this item from treeview by iid when iid =0.
There is no item with such iid. This item has autogenerated iid just like it's not specified.
I investigated problem and found that in ttk.py, Treeview.insert(... iid=None, ...) in method's body has a check:
        if iid:
            res = self.tk.call(self._w, "insert", parent, index,
                "-id", iid, *opts)
        else:
            res = self.tk.call(self._w, "insert", parent, index, *opts)
It means that if iid is "True" then use it else autogenerate it.
Maybe there should be "if iid is not None", not "if iid"? Or there are some reasons to do check this way?

Igor Yakovchenko

Без вирусов. www.avast.ru

Terry Reedy

unread,
Mar 16, 2018, 4:24:17 PM3/16/18
to pytho...@python.org
On 3/16/2018 6:54 AM, Игорь Яковченко wrote:

This might fit python-list better, and may become a bugs.python.org
issue, but I will answer now, having just investigated.

> I found a possible bug with ttk.Treeview widget.

See below.

> I'm working on program that uses tkinter UI. I use ttk.Treeview to
> display some objects and I want to use integer iid of items.

For tk, the underlying graphics framework, iids are strings. "If iid is
specified, it is used as the item identifier", from the Treeview doc,
oversimplifies. When iid is specified, the iid used internally and
returned by Treeview() is a string based on the value passed. 1 becomes
'1', 1.0 becomes '1.0', (1,2,3) and [1,2,3] both become '1 2 3' (this is
consistent in tkinter), and int becomes "<class 'int'>". Since the
transformation is the same when referencing an item, as with
tv.index(iid), one can usually ignore it. But it shows up if one prints
a return value (as I did to discover the above), or tries to compare it
with the original objects, or tries to use two different objects with
the same tk string as iids.

> For example, I insert a row with treeview.insert(... iid=0, ...).
> But I
> encountered a problem when I try to get this item from treeview by iid
> when iid =0.

Other things being equal, I agree that one should be able to pass 0 and
0.0 along with all other ints and floats. In the meanwhile, you could
pass '0' and retrieve with either '0' or 0. To not special-case 0,
always pass iid=int(row).

> There is no item with such iid. This item has autogenerated iid just
> like it's not specified.
> I investigated problem and found that in ttk.py, Treeview.insert(...
> iid=None, ...) in method's body has a check:
>         if iid:
>             res = self.tk.call(self._w, "insert", parent, index,
>                 "-id", iid, *opts)
>         else:
>             res = self.tk.call(self._w, "insert", parent, index, *opts)
> It means that if iid is "True" then use it else autogenerate it.
> Maybe there should be "if iid is not None", not "if iid"? Or there are
> some reasons to do check this way?

It might be that accepting '' as an iid would be a problem.
Our current tkinter expert, Serhiy Storchaka, should know. If so, "if
iid in (None, '')" would be needed.

--
Terry Jan Reedy


_______________________________________________
Python-Dev mailing list
Pytho...@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: https://mail.python.org/mailman/options/python-dev/dev-python%2Bgarchive-30976%40googlegroups.com

MRAB

unread,
Mar 16, 2018, 8:40:55 PM3/16/18
to pytho...@python.org
On 2018-03-16 20:22, Terry Reedy wrote:
> On 3/16/2018 6:54 AM, Игорь Яковченко wrote:
[snip]

>> There is no item with such iid. This item has autogenerated iid just
>> like it's not specified.
>> I investigated problem and found that in ttk.py, Treeview.insert(...
>> iid=None, ...) in method's body has a check:
>>         if iid:
>>             res = self.tk.call(self._w, "insert", parent, index,
>>                 "-id", iid, *opts)
>>         else:
>>             res = self.tk.call(self._w, "insert", parent, index, *opts)
>> It means that if iid is "True" then use it else autogenerate it.
>> Maybe there should be "if iid is not None", not "if iid"? Or there are
>> some reasons to do check this way?
>
> It might be that accepting '' as an iid would be a problem.
> Our current tkinter expert, Serhiy Storchaka, should know. If so, "if
> iid in (None, '')" would be needed.
>

The root of the tree has the iid ''.

Chris Barker

unread,
Mar 20, 2018, 8:04:50 PM3/20/18
to Игорь Яковченко, Python Dev
On Fri, Mar 16, 2018 at 10:54 AM, Игорь Яковченко <truest...@gmail.com> wrote:
I investigated problem and found that in ttk.py, Treeview.insert(... iid=None, ...) in method's body has a check:
        if iid:
            res = self.tk.call(self._w, "insert", parent, index,
                "-id", iid, *opts)
        else:
            res = self.tk.call(self._w, "insert", parent, index, *opts)
It means that if iid is "True" then use it else autogenerate it.
Maybe there should be "if iid is not None", not "if iid"? Or there are some reasons to do check this way?
 
isn't it considered pythonic to both: use None as a default for "not specified" AND use:

if something is None

to check if the parameter has been specified?

however, this is a bit of an odd case:

ids are strings, but it allows you to pass in a non-string and stringified version will be used.

so None should be the only special case -- not "anything false"

(but if the empty string is the root, then it's another special case -- again, good to check for none rather than anything Falsey)

so it probably should do something like:


      if iid is not None:
            res = self.tk.call(self._w, "insert", parent, index,
                "-id", str(iid), *opts)
        else:
            res = self.tk.call(self._w, "insert", parent, index, *opts)

note both the check for None and the str() call.
 
I'm assuming the str() call happens under the hood at the boundary already, but better to make it explicit in teh Python.

Alternatively: this has been around a LONG time, so the maybe the answer is "don't do that" -- i.e. don't use anything falsey as an iid. But it would still be good to make the docs more clear about that.

-CHB

-------
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

Chris....@noaa.gov

Igor Yakovchenko

unread,
Mar 24, 2018, 2:10:57 AM3/24/18
to pytho...@python.org
I had opened a tracker issue <https://bugs.python.org/issue33096>.

--
Igor Yakovchenko

Без вирусов. www.avast.ru
Reply all
Reply to author
Forward
0 new messages