Tkinter Treeview绑定<ButtonPress-1>时selection()获取选中项异常
问题原因
绑定<ButtonPress-1>时,你的状态检查函数会在Treeview内部完成选中状态更新之前被触发。Tkinter中Treeview的选中逻辑属于按钮按下事件的后续处理环节,所以此时调用tree.selection()只能拿到上一次的选中结果,就出现了你遇到的延迟错位问题。
方案1:使用Treeview专属选中事件(推荐)
Treeview自带<<TreeviewSelect>>事件,这个事件会在选中状态真正更新完成后触发,不仅响应即时,还能正确获取最新选中项,同时兼容键盘操作(比如用上下箭头切换选中行),是处理这类需求的标准方式。
只需要把原来的事件绑定代码替换成:
tree.bind('<<TreeviewSelect>>', disablebutton_statecheck)
方案2:强制延迟执行状态检查(仅当必须用时)
如果因为特殊需求必须绑定<ButtonPress-1>,可以通过after_idle()让状态检查逻辑在Tkinter处理完当前所有待处理事件(包括Treeview的选中更新)后再执行:
修改状态检查函数和事件绑定:
def disablebutton_statecheck(event=None): # 让Tk先处理完所有待处理事件,再执行选中状态检查 window.after_idle(_check_selection) def _check_selection(): print("triggered statecheck") selected_items = list(tree.selection()) print(selected_items) print(len(selected_items)) if len(selected_items) > 0: button_6.state(["!disabled"]) else: button_6.state(["disabled"]) # 绑定<ButtonPress-1>事件 tree.bind('<ButtonPress-1>', disablebutton_statecheck)
这样就能保证调用tree.selection()时,Treeview已经完成了选中状态的更新。
完整修复代码(方案1版本)
import tkinter as tk from tkinter import * from tkinter import ttk alternate = 1 def add_row(): global alternate if alternate == 0: tree.insert('', tk.END,text="L1",values=("Big1","Test12345")) alternate = 1 elif alternate == 1: tree.insert('', tk.END,text="L1",values=("Big1","Test")) alternate = 0 def delete_row(): last = tree.get_children()[-1] tree.delete(last) disablebutton_statecheck() def disablebutton_statecheck(event=None): print("triggered statecheck") print(list(tree.selection())) print(len(tree.selection())) if len(tree.selection()) > 0: button_6.state(["!disabled"]) else: button_6.state(["disabled"]) window = Tk() window.title("test window") window.geometry("600x600+0+0") section_1 = Frame(window, width = 600, height = 600, bg="#faf") section_1.place(x=0, y=0) tabControl_1 = ttk.Notebook(section_1, height = 470, width = 395) #395 tab1 = ttk.Frame(tabControl_1) tabControl_1.add(tab1, text='Devices') tabControl_1.place(y=10,x=25) tree = ttk.Treeview(tab1, height=7) tree.place(x=30, y=95) tree.bind('<Motion>', 'break') tree["columns"] = ("one", "two") tree['show'] = 'headings' tree.column("one", width=100, anchor='c', stretch=False) tree.column("two", width=100, anchor='c', stretch=False) tree.heading("one", text="Account") tree.heading("two", text="Type") tree.insert("",'end', text="L1",values=("Test","Test12345")) button_1 = ttk.Button(tab1, text="add a row", command=add_row, width=17) button_1.place(x=50, y=360) button_2 = ttk.Button(tab1, text="delete row", command=delete_row, width=17) button_2.place(x=200, y=360) button_6 = ttk.Button(tab1, text="disable", width=17) button_6.place(x=50, y= 50) # 替换为Treeview专属选中事件 tree.bind('<<TreeviewSelect>>', disablebutton_statecheck) disablebutton_statecheck() window.resizable(False,False) window.mainloop()
内容的提问来源于stack exchange,提问作者Jones659
相关产品推荐
相关产品推荐

