触发回调时,tkinter 树视图打开状态不是最新的

tkinter treeview open state is not up to date when callback is triggered

我目前正在开发一个 tkinter 应用程序,它使用 treeview 元素在层次结构中显示数据。在这个应用程序的一部分,我需要更新项目的数据。不幸的是,获取这些数据非常昂贵(在时间和处理方面),所以我现在只更新当前可见的项目。

我遇到的问题是,当我将一个(左键单击)事件绑定到一个项目,然后在树视图中查询打开的项目以尝试确定可见的项目时,之前打开的项目被 returned ,但当前打开的项目不是(直到单击后续项目)。

我看到this question关于查询(和设置)打开状态,但它似乎不能满足我的需求。

我有以下简化的代码,它演示了问题:

## import required libraries
import tkinter
import tkinter.ttk
import random
import string

## event handler for when items are left clicked
def item_clicked(event):        
    tree = event.widget
    
    ## we assume event.widget is the treeview    
    current_item = tree.item(tree.identify('item', event.x, event.y))
    print('Clicked ' + str(current_item['text']))
    
    ## for each itewm in the treeview
    for element in tree.get_children():    
        ## if it has elements under it..
        if len(tree.get_children(element)) > 0:
            ## get the element name
            element_name = tree.item(element)['text']
            ## check if it is open
            if tree.item(element)['open'] is True:
                print('Parent ' + element_name + ' is open')
            else:
                print('Parent ' + element_name + ' is closed')
 
## make the window and treeview
root = tkinter.Tk()
root.title('Treeview test')
tree = tkinter.ttk.Treeview(root, selectmode = 'browse', columns = ('num', 'let'))
tree.heading('#0', text = 'Name')
tree.heading('num', text = 'Numbers')
tree.heading('let', text = 'Letters')
tree.bind('<Button-1>', item_clicked)
tree.pack()

## populate the treeview with psuedo-random data
parents = ['']
for i in range(100):
    id = str(i)
    ## higher probability that this won't be under anything
    if random.randrange(50) > 40:
        parent = random.choice(parents)
    else:
        parent = ''
        
    ## make up some data
    tree.insert(parent, 'end', iid = id, text = 'Item ' + id)
    tree.set(id, 'num', ''.join(random.choices(string.digits, k=10)))
    tree.set(id, 'let', ''.join(random.choices(string.ascii_uppercase, k=10)))
    
    parents.append(id)

## main event loop (blocking)    
root.mainloop()

此代码将生成一个包含 100 个随机继承项的树视图。单击任何项​​目将打印具有子项且当前已展开(打开)的项目列表。问题是,与我的主要代码一样,没有报告最新打开的项目(即落后一步)。

在查询其状态之前(在 item_clicked 函数的开头)向树视图添加 update() 无法解决问题。

运行 在 Windows 10 上 Python 3.7.3(Tk 版本 8.6.9)。

将上述代码中的事件绑定从 <Button-1> 更改为 <ButtonRelease-1> 可解决问题。

在上面的代码中应该注意的是,open/close 状态只会被打印出没有父项的子项(即它不会下降到树中)。要解决此问题,您只需要递归地对每个包含子项的项目调用 tree.get_children(item_id)