【问题标题】:How to swap widget placement in a tkinter grid using drag and drop?如何使用拖放交换 tkinter 网格中的小部件放置?
【发布时间】:2021-06-09 10:05:18
【问题描述】:

我正在尝试使用拖放在 tkinter 的网格布局中交换两个小部件的位置。在鼠标 ButtonRelease-1 上,我想获取释放鼠标的小部件 (myTextLabel2),以便我可以使用单击的小部件 (myTextLabel1) 的行和列更改该小部件的行和列。

我尝试搜索在位置 x,y 处获取小部件的方法,但我只能找到相反的方法,获取小部件的位置而不是相反。

到目前为止,这是我的代码:

from tkinter import *
from functools import partial

def changeOrder(widget1,widget2):
    widget1.grid(row=1,column=0)
    widget2.grid(row=0,column=0)

def drag_start(event):
    print(event.x)

def drag_motion(event):
    x = event.x
    y = event.y
    

def drag_release(event):
    x = event.x
    y = event.y
    #I want to get the widget at position x,y, should be myTextLabel2

    #Then swap the rows and columns for myTextLabel2 and myTextLabel1
    

root = Tk()


myTextLabel1 = Label(root,text="Label 1")
myTextLabel1.grid(row=0,column=0,padx=5,pady=5,sticky=E+W+S+N)
myTextLabel1.bind("<Button-1>",drag_start)
myTextLabel1.bind("<B1-Motion>",drag_motion)
myTextLabel1.bind("<ButtonRelease-1>",drag_release)


myTextLabel2 = Label(root,text="Label 2")
myTextLabel2.grid(row=1,column=0,padx=5,pady=5,sticky=E+W+S+N)


myButton = Button(root,text="Change order",command=partial(changeOrder,myTextLabel1,myTextLabel2))
myButton.grid(row=3,column=0,padx=5,pady=5,sticky=E+W+S+N)


root.mainloop()

【问题讨论】:

    标签: python tkinter


    【解决方案1】:

    你可以试试这样的

    from tkinter import *
    from functools import partial
    
    def changeOrder(widget1,widget2,initial):
        target=widget1.grid_info()
        widget1.grid(row=initial['row'],column=initial['column'])
        widget2.grid(row=target['row'],column=target['column'])
    
    def on_click(event):
        widget=event.widget
        print(widget) 
        if isinstance(widget,Label):
            start=(event.x,event.y)
            grid_info=widget.grid_info()
            widget.bind("<B1-Motion>",lambda event:drag_motion(event,widget,start))
            widget.bind("<ButtonRelease-1>",lambda event:drag_release(event,widget,grid_info))
        else:
            root.unbind("<ButtonRelease-1>")
    
    def drag_motion(event,widget,start):
        x = widget.winfo_x()+event.x-start[0]
        y = widget.winfo_y()+event.y-start[1] 
        widget.lift()
        widget.place(x=x,y=y)
    
    def drag_release(event,widget,grid_info):
        widget.lower()
        x,y=root.winfo_pointerxy()
        target_widget=root.winfo_containing(x,y)
        if isinstance(target_widget,Label):
            changeOrder(target_widget,widget,grid_info)
        else:
            widget.grid(row=grid_info['row'],column=grid_info['column'])
    
    root = Tk()
    
    myTextLabel1 = Label(root,text="Label 1",bg='yellow')
    myTextLabel1.grid(row=0,column=0,padx=5,pady=5,sticky=E+W+S+N)
    
    myTextLabel2 = Label(root,text="Label 2",bg='lawngreen')
    myTextLabel2.grid(row=1,column=0,padx=5,pady=5,sticky=E+W+S+N)
    
    myButton = Button(root,text="Change order",command=partial(changeOrder,myTextLabel1,myTextLabel2))
    myButton.grid(row=3,column=0,padx=5,pady=5,sticky=E+W+S+N)
    
    root.bind("<Button-1>",on_click)
    
    root.mainloop()
    
    • root.bind("&lt;Button-1&gt;",on_click) 已用于将整个窗口与&lt;Button-1&gt; 事件绑定,如果单击的小部件是Label 的实例,则函数on_click 添加其他2 个绑定。标签的grid_info() 被存储并相应地传递。
    • drag_motion 使用 place 根据运动改变小部件的位置,并使用 lift 方法将小部件保持在顶部。
    • drag_release 使用lower 方法降低小部件,然后使用winfo_pointerxy 方法获取光标的当前位置并将返回值传递给winfo_containing 方法,该方法返回鼠标指针下的小部件。

    您可以替换 isinstance 逻辑,方法是将可交换的小部件存储在列表中,然后检查小部件是否位于其中。

    PS:由于对代码所做的更改,您原始帖子中的按钮将无法使用。

    【讨论】:

    • 要使按钮现在可以工作,您必须将myTextLabel2.grid_info() 作为最后一个参数传递,即使在此之后,由于功能的更改,它也只能正常工作一次。无论如何,我认为这不是问题的一部分。
    • @CoolCloud 会的,谢谢指出。
    猜你喜欢
    • 2016-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-12
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    相关资源
    最近更新 更多