触发回调时,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() 无法解决问题。
- 如何在上述代码的事件处理程序中准确获取项目的打开状态?
- 在项目实际展开(打开)之前触发事件是否是一个问题,如果是这样,为什么 update() 没有解决这个问题?
- 树视图小部件是否存在 return 当前可见项目列表的替代功能?
运行 在 Windows 10 上 Python 3.7.3(Tk 版本 8.6.9)。
将上述代码中的事件绑定从 <Button-1>
更改为 <ButtonRelease-1>
可解决问题。
在上面的代码中应该注意的是,open/close 状态只会被打印出没有父项的子项(即它不会下降到树中)。要解决此问题,您只需要递归地对每个包含子项的项目调用 tree.get_children(item_id)
。
我目前正在开发一个 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() 无法解决问题。
- 如何在上述代码的事件处理程序中准确获取项目的打开状态?
- 在项目实际展开(打开)之前触发事件是否是一个问题,如果是这样,为什么 update() 没有解决这个问题?
- 树视图小部件是否存在 return 当前可见项目列表的替代功能?
运行 在 Windows 10 上 Python 3.7.3(Tk 版本 8.6.9)。
将上述代码中的事件绑定从 <Button-1>
更改为 <ButtonRelease-1>
可解决问题。
在上面的代码中应该注意的是,open/close 状态只会被打印出没有父项的子项(即它不会下降到树中)。要解决此问题,您只需要递归地对每个包含子项的项目调用 tree.get_children(item_id)
。