用Tkinter打造GUI开发工具(46)在Tkinter中实现控件拖拽功能

用Tkinter打造GUI开发工具(46)在Tkinter中实现控件拖拽功能
Python已经升级到Python 3.8版本了,Tkinter库仍然是自带GUI开发库。
原生tkinter.dnd模块就提供了控件拖拽的演示,这个是不同tk窗口中拖拽控件的演示。
在C:\Python\Lib\tkinter目录中可以找到dnd.py这个文件,原始文件读者自己运行尝试。
如果在一个窗口中的不同区域怎么移动控件呢?
因此我在tkinter.dnd模块进一步封装,可以实现不同区域或不同窗口中的控件拖动。
我们使用HP_tk2的View控件,把窗口划分为四个区域,在这四个区域中,做演示。
下面我直接给出源代码。

import  tkinter  as  tk   #导入Tkinter
import tkinter.dnd as dnd
import HP_tk2 as htk
#独狼荷蒲qq:2886002
#通通小白python量化群:524949939
#微信公众号:独狼股票分析
class  dndIcon:
    def __init__(self, idname = None):
        self.idname = idname
        self.canvas = None
        self.label = None
        self.id = None

    def attach(self, canvas, x=10, y=10):
        if canvas is self.canvas:
            self.canvas.coords(self.id, x, y)
            return
        if self.canvas:
            self.detach()
        if not canvas:
            return
        id = canvas.create_window(x, y, window=self.idname, anchor="nw")
        self.canvas = canvas
        self.id = id
        self.idname.bind("<ButtonPress>", self.press)

    def detach(self):
        canvas = self.canvas
        if not canvas:
            return
        id = self.id
        label = self.label
        self.canvas = self.label = self.id = None
        canvas.delete(id)
        self.idname.place_forget()

    def press(self, event):
        if dnd.dnd_start(self, event):
            # where the pointer is relative to the label widget:
            self.x_off = event.x
            self.y_off = event.y
            # where the widget is relative to the canvas:
            self.x_orig, self.y_orig = self.canvas.coords(self.id)

    def move(self, event):
        x, y = self.where(self.canvas, event)
        self.canvas.coords(self.id, x, y)

    def putback(self):
        self.canvas.coords(self.id, self.x_orig, self.y_orig)

    def where(self, canvas, event):
        # where the corner of the canvas is relative to the screen:
        x_org = canvas.winfo_rootx()
        y_org = canvas.winfo_rooty()
        # where the pointer is relative to the canvas widget:
        x = event.x_root - x_org
        y = event.y_root - y_org
        # compensate for initial pointer offset
        return x - self.x_off, y - self.y_off

    def dnd_end(self, target, event):
        pass


#可拖拽控件的控件
class dndwidget(tk.Frame):
    def __init__(self, master,**kw):
        tk.Frame.__init__(self, master,**kw)  
        self.top = master
        self.canvas = tk.Canvas(self.top, width=100, height=100,**kw)
        self.canvas.pack(fill="both", expand=1)
        self.canvas.dnd_accept = self.dnd_accept

    def dnd_accept(self, source, event):
        return self

    def dnd_enter(self, source, event):
        self.canvas.focus_set() # Show highlight border
        x, y = source.where(self.canvas, event)
        x1, y1, x2, y2 = source.canvas.bbox(source.id)
        dx, dy = x2-x1, y2-y1
        self.dndid = self.canvas.create_rectangle(x, y, x+dx, y+dy)
        self.dnd_motion(source, event)

    def dnd_motion(self, source, event):
        x, y = source.where(self.canvas, event)
        x1, y1, x2, y2 = self.canvas.bbox(self.dndid)
        self.canvas.move(self.dndid, x-x1, y-y1)

    def dnd_leave(self, source, event):
        self.top.focus_set() # Hide highlight border
        self.canvas.delete(self.dndid)
        self.dndid = None

    def dnd_commit(self, source, event):
        self.dnd_leave(source, event)
        x, y = source.where(self.canvas, event)
        source.attach(self.canvas, x, y)
          



def test2():
    root = tk.Tk()
    root.geometry('{}x{}+{}+{}'.format(800,600, 250, 350)) #改变窗口位置和大小
    root.title('dnd拖拽演示')
    v=htk.View(root,kind='田')
    v.pack()
    t1 = dndwidget(v.v[0])
    t2 = dndwidget(v.v[1],bg='green')
    t3 = dndwidget(v.v[2],bg='yellow')
    t4 = dndwidget(v.v[3],bg='blue')
    
    i1 = dnd.Icon("ICON1")
    i2 = dnd.Icon("ICON2")
    i3 = dnd.Icon("ICON3")
    bt=tk.Button(v.v[3], text="Quit")
    i4 = dndIcon(bt)
    
    i1.attach(t1.canvas)
    i2.attach(t2.canvas)
    i3.attach(t3.canvas)    
    i4.attach(t4.canvas)    
    root.mainloop()
    

if __name__ == '__main__':
    test2()

程序运行结果如下。
在这里插入图片描述
读者可以根据我的思路来完善Tkinter的拖拽功能。

猜你喜欢

转载自blog.csdn.net/hepu8/article/details/108035629