PythonTreeView 节点支持鼠标、键盘移动代码

涉及表格的编程时,都会用上 TreeView 组件,每次写节点移动都要纠结半天,现总结了一下,把这些功能汇总给大家,直接可以拿来就用

特点:支持鼠标多选(需要Shift、Ctrl)键配合多选,然后用鼠标拖动,同时支持用键盘的上、下方向键移动,Home、End 键则为置顶、置底

大家可以直接使用,不费话,上原码:

import tkinter as tk
from tkinter import ttk

def bDown_Shift(event):
    tv = event.widget
    select = [tv.index(s) for s in tv.selection()]
    select.append(tv.index(tv.identify_row(event.y)))
    select.sort()
    for i in range(select[0],select[-1]+1,1):
        tv.selection_add(tv.get_children()[i])

def bDown(event):
    tv = event.widget
    if tv.identify_row(event.y) not in tv.selection():
        tv.selection_set(tv.identify_row(event.y))    

def bUp(event):
    pass

def bUp_Shift(event):
    pass

def bMove(event):
    tv = event.widget
    i=tv.identify_row(event.y)
    if i=="":
        return

    moveto = tv.index(i)
    total=tv.selection()
    t1=tv.index(total[0])
    t2=tv.index(total[-1])
    sel=list(tv.selection())
    sel.sort()
    if moveto>=t1 and moveto<=t2:
        return
    if moveto>t2:
        for s in sel:
            tv.move(s, '', moveto)
    else:
        for s in reversed( sel):
            tv.move(s, '', moveto)


def bDown_Ctrl(event):
    #print(11)
    tv = event.widget
    if tv.identify_row(event.y) not in tv.selection():
        tv.selection_add(tv.identify_row(event.y))

def bUp_Ctrl(event):
    pass

def keyboard(event):
    #print(event.keycode)
    tv = event.widget
    items=tv.selection()
    if event.keycode==38:
        musicMoveUp()# 上移
    elif event.keycode==40:
        musicMoveDown()# 下移
    elif event.keycode==36: 
        musicMoveTop()# Home  置顶
    elif event.keycode==35:
        musicMoveBottom() # End  置底

def musicMoveUp():#上移
    items=tree.selection() #选择的总数
    if len(items)==0:
        return

    intConnect=0#连接计数,即选中的在最前面的连续数
    intCount=0 #选中计数器
    for item in items:
        intIndex=tree.index(item)
        if intConnect==intIndex:
            intConnect=intConnect+1
        intCount=intCount+1#选中计数器
        if intIndex>0 and tree.index(items[-1])+1>len(items) and intConnect!=intCount:
            tree.move(item,'',intIndex-1)


    #
def musicMoveTop():#置顶
    #if tree.curselection():#是否存在选择中项目
    items=tree.selection() #选择的总数
    if len(items)==0:
        return

    for item in reversed(items): #倒序
        intIndex=tree.index(item)
        if intIndex>0:
            tree.move(item,tree.parent(item),0)

    tree.see(item)


    #
def musicMoveDown():#下移
    items=tree.selection() #选择的总数
    if len(items)==0:
        return

    item=items[0] #取第1个选中的来得到该树枝的子项目数

    intTotalChildren=len(tree.get_children(tree.parent(item)))
    intConnect=intTotalChildren-1#连接计数,即选中的在最后面的连续数
    intCount=intTotalChildren-1 #选中计数器
    for item in reversed(items): #倒序
        intIndex=tree.index(item)
        if intConnect==intIndex:
            intConnect=intConnect-1
        intCount=intCount-1#选中计数器
        if intIndex<intTotalChildren and tree.index(items[0])+len(items)<intTotalChildren and intConnect!=intCount:
            tree.move(item,'',intIndex+1)


def musicMoveBottom():#置底
    items=tree.selection() #选择的总数
    if len(items)==0:
        return

    intTotalChildren=len(tree.get_children(tree.parent(items[0])))
    for item in items:
        intIndex=tree.index(item)
        if intIndex<intTotalChildren-1:
            tree.move(item,tree.parent(item),tk.END)

    tree.see(item)


root = tk.Tk()

tree = ttk.Treeview(columns=("col1","col2"), 
                    displaycolumns="col2", 
                    selectmode='none')


for i in range(10):
    tree.insert('', 'end',iid='line%i' % i, text='line:%s' % i, values=('', i))

tree.grid()
tree.bind("<ButtonPress-1>",bDown)
tree.bind("<ButtonRelease-1>",bUp)#, add='+')
tree.bind("<B1-Motion>",bMove)#, add='+')
tree.bind("<Shift-ButtonPress-1>",bDown_Shift)#, add='+')
tree.bind("<Shift-ButtonRelease-1>",bUp_Shift)#, add='+')
tree.bind("<Control-ButtonPress-1>",bDown_Ctrl)#, add='+')
tree.bind("<Control-ButtonRelease-1>",bUp_Ctrl)#, add='+'
tree.bind('<Key>',keyboard)

root.mainloop()
下面是一个C# TreeView控件选择多个节点拖拽移动的示例代码: ```csharp private List<TreeNode> selectedNodes = new List<TreeNode>(); private Point mouseDownLocation; private void treeView1_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left && ModifierKeys == Keys.Control) { //记录用户选择的节点 selectedNodes.Clear(); foreach (TreeNode node in treeView1.SelectedNodes) { selectedNodes.Add(node); } //记录鼠标按下的位置 mouseDownLocation = e.Location; } } private void treeView1_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left && selectedNodes.Count > 0) { //如果移动了一定的距离,开始拖拽操作 if (Math.Abs(e.X - mouseDownLocation.X) > SystemInformation.DragSize.Width || Math.Abs(e.Y - mouseDownLocation.Y) > SystemInformation.DragSize.Height) { //开始拖拽操作 treeView1.DoDragDrop(selectedNodes, DragDropEffects.Move); } } } private void treeView1_DragOver(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(typeof(List<TreeNode>))) { //判断鼠标位置是否在TreeView控件上 Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y)); TreeNode targetNode = treeView1.GetNodeAt(targetPoint); if (targetNode != null && targetNode.IsVisible) { e.Effect = DragDropEffects.Move; //展开目标节点 targetNode.Expand(); } else { e.Effect = DragDropEffects.None; } } } private void treeView1_DragDrop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(typeof(List<TreeNode>))) { //获取拖拽操作的源节点和目标节点 Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y)); TreeNode targetNode = treeView1.GetNodeAt(targetPoint); List<TreeNode> draggedNodes = (List<TreeNode>)e.Data.GetData(typeof(List<TreeNode>))); //循环将所有源节点移动到目标节点下面 foreach (TreeNode node in draggedNodes) { if (node.Parent != targetNode) { node.Remove(); targetNode.Nodes.Add(node); } } //选中移动后的节点 treeView1.SelectedNodes = draggedNodes; } } ``` 在上述代码中,我们首先在MouseDown事件中记录用户选择的节点,并记录鼠标按下的位置。然后在MouseMove事件中,如果移动了一定的距离,就开始拖拽操作。在DragOver事件中,判断鼠标位置是否在TreeView控件上,并展开目标节点。在DragDrop事件中,获取拖拽操作的源节点和目标节点,并循环将所有源节点移动到目标节点下面。最后,选中移动后的节点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jumpbull01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值