python tkinter treeview 表格全选、鼠标拖拽选中表格

在网上有很多tkinter相关的教学,也有很多treeview相关方法的介绍,但是treeview表格选中相关的介绍比较少,这里分享一下个人使用过程中的经验。

与选中相关有两个函数,一个是selection,一个是selection_set。

可以用selection函数获取集合,包含了所有选中的单元的iid。

在treeview中,选中单位可以用selection_set函数设定,这个函数的对象是treeview类,方法的参数是目标的iid。如果传入参数是一个iid,只选择一个目标,如果传入列表等,就会选中多行目标。

全选表格

我们可以遍历整个表格,把每一行的iid保存到一个列表中,然后将列表传递给selection_set函数,就可以选中整个表格。

import tkinter as tk
from tkinter import ttk
 
def select_all_items(tree):
    select = []
    for item in tree.get_children():
        select.append(item)
    tree.selection_set(select)
    print(tree.selection()) #打印查看选中行的iid
 
root = tk.Tk()
tree = ttk.Treeview(root)
tree.pack(fill=tk.BOTH, expand=True)
 
# 假设你已经填充了treeview,下面是添加条目的示例代码
for i in range(5):
    tree.insert('', 'end', text=f"Item {i}")
 
# 全选按钮
select_all_button = ttk.Button(root, text="Select All", command=lambda: select_all_items(tree))
select_all_button.pack()
 
root.mainloop()

这段代码基于百度ai,但是ai直接生成的代码有问题。他每次传入一个位置,运行的时候速度太快,人是看不见的,最后结果是选中了最后一个选项。

鼠标拖拽选中

绑定事件

鼠标拖拽主要有三个动作,按下鼠标、移动、松开,我们可以用三个函数处理对应的操作并绑定到事件。

# 绑定事件
tree.bind("<ButtonPress-1>", self.on_mouse_click)
tree.bind("<ButtonRelease-1>", self.on_mouse_release)
tree.bind("<B1-Motion>", self.on_mouse_motion)

选中区域管理

我们在选中区域的时候,会有一个起点位置,这个位置无论如何最终都会被选中。当我们把鼠标远离起点位置时,会加入更多的行,反过来靠近时则会去掉多余的行。在行的进出过程中,其顺序符合先入后出的原则,所以我们用一个类似队列的结构去管理我们要选中的区域。

按下鼠标

按下鼠标后进入事件处理函数,首先判断事件是否和我们的表格相关。将鼠标位置的行作为第一个元素加入队列中,然后用一个布尔类记录启动信号,表示已经开始拖拽。

# 如果是按下左键,开始拖拽选择
tree = self.tree
if event.widget == tree:
    self.selection_trace = [tree.identify_row(event.y)]
    tree.selection_set(tree.identify_row(event.y))
    self.drag_start.set(True)

 移动鼠标

每次移动鼠标,我们首先获取当前所在行的iid。当我们移动到新的一行,就把新的一行加入到队列,如果回到上一行,就把队尾的元素踢出。这样的话,我们的队列中,队尾是上一次加入的新元素,队尾的前一个是上次加入的元素(如果有的话)。

如果鼠标在同一行移动,每次获取的都是同一行,应当与队尾为同一行,因此要判断是否在同一行移动。如果在同一行,就不做任何处理。

if next_row == self.selection_trace[-1]: #原来行没变
    return

 假设起点在上方,鼠标往下移动移动到新的行,往上移动到原来行位置。原来行对应队列中倒数第二个元素,新的行在队列中没有元素,需要比较当前行的位置判断移动方向。由于最开始的时候队列中只有一个元素,使用下标访问[-2]会越界,因此先判断队列的长度。

if len(self.selection_trace) == 1 or next_row != self.selection_trace[-2]:
    self.selection_trace.append(next_row)

 如果队列中倒数第二个元素与当前行相同,说明鼠标往上走也就是回去了,这时候就抛出队尾。

tree.selection_set(self.selection_trace)

 这部分代码合起来

# 如果已经开始拖拽,更新选择区域
tree = self.tree
if event.widget == tree and self.drag_start.get():
    next_row = tree.identify_row(event.y)
    if next_row == self.selection_trace[-1]: #原来行没变
        return
    if len(self.selection_trace) == 1 or next_row != self.selection_trace[-2]:
        self.selection_trace.append(next_row)
    else: #回去一行
        self.selection_trace.pop(-1)
    tree.selection_set(self.selection_trace)

 松开鼠标

将开始的标志赋值为否,表示拖拽选中已经停止。

def on_mouse_release(self, event):
    # 如果是释放左键,结束拖拽选择
    tree = self.tree
    if event.widget == tree and self.drag_start.get():
        self.drag_start.set(False)

 完整的代码如下,额外添加了右键选中。

import tkinter as tk
from tkinter import ttk

class drag_select_tree:
    def __init__(self, root):
        self.root = root
        self.drag_start = tk.BooleanVar() # 开始拖拽选择的标志
        self.drag_start.set(False)
        self.create_tree()
        
    def create_tree(self):
        tree = ttk.Treeview(root, columns=("Size", "Modified"), selectmode='extended')
        tree.pack(fill="both", expand=True)
        self.tree = tree
         
        # 创建示例数据
        for i in range(10):
            tree.insert("", "end", text=f"Item {i}", values=(f"Size {i}", f"Modified {i}"))

        # 绑定事件
        tree.bind("<ButtonPress-1>", self.on_mouse_click)
        tree.bind("<ButtonPress-3>", self.on_mouse_click)
        tree.bind("<ButtonRelease-1>", self.on_mouse_release)
        tree.bind("<ButtonRelease-3>", self.on_mouse_release)
        tree.bind("<B1-Motion>", self.on_mouse_motion)
        tree.bind("<B3-Motion>", self.on_mouse_motion)
        
    def on_mouse_click(self, event):
        # 如果是按下左键,开始拖拽选择
        tree = self.tree
        if event.widget == tree:
            self.selection_trace = [tree.identify_row(event.y)]
            tree.selection_set(tree.identify_row(event.y))
            self.drag_start.set(True)
     
    def on_mouse_release(self, event):
        # 如果是释放左键,结束拖拽选择
        tree = self.tree
        if event.widget == tree and self.drag_start.get():
            self.drag_start.set(False)
     
    def on_mouse_motion(self, event):
        # 如果已经开始拖拽,更新选择区域
        tree = self.tree
        if event.widget == tree and self.drag_start.get():
            next_row = tree.identify_row(event.y)
            if next_row == self.selection_trace[-1]: #原来行没变
                return
            if len(self.selection_trace) == 1 or next_row != self.selection_trace[-2]:
                self.selection_trace.append(next_row)
            else: #回去一行
                self.selection_trace.pop(-1)
            tree.selection_set(self.selection_trace)
 
root = tk.Tk()
drag_select_tree(root)

root.mainloop()

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值