Python实现用鼠标拖动Canvas上的图形或图像使其移动(有问题参见后边文章)

程序有时需要用鼠标拖动图形或图像使其移动,例如,win10画图程序完成画圆后,鼠标抬起,此时仍然允许用鼠标拖动这个图形或图像实例使其移动。如鼠标再一次点击要移动的图形或图像上,并且鼠标左键保持按下状态移动,则用Canvas方法move移动这个图形或图像,移动的增量是鼠标移动的当前位置减去鼠标移动的前一位置,直到鼠标单击处不在这个图形或图像上,将把这个图形或图像变为位图,不能再以图形或图像实例方式移动。又如EDA程序,所有器件封装图和器件封装之间连线在设计完成前都是图形或图像的实例,经常要用鼠标移动这些图形或图像。本文用python实现该功能。
程序首先在Canvas上画了一条线段,一个矩形和一个圆,其中cv是Canvas实例。请注意activefill=‘red’,当鼠标移到该线段上,线段变红色,当鼠标移到矩形和圆上,它们内部变红色,通知鼠标在此处单击能单击到该实例。

cv.create_line(10, 10, 50, 50, activefill='red')
cv.create_oval(10,70,100,160,activefill='red')
cv.create_rectangle(50,120,150,180,fill='#CCFFFF',activefill='red')

然后为事件绑定事件函数如下:

cv.bind("<ButtonPress-1>",StartMove)  #绑定鼠标左键按下事件
cv.bind("<ButtonRelease-1>",StopMove) #绑定鼠标左键松开事件
cv.bind("<B1-Motion>", OnMotion)      #绑定鼠标左键被按下时移动鼠标事件

在鼠标左键按下事件函数StartMove中,首先要确定单击了那个实例,代码如下。第一条语句找到鼠标所在坐标处图形图像实例的ID值,可能有多个实例,所以返回一个列表,如列表长度为0,表示点击处无实例,否则有实例。如果有多个,最近的应是列表的第0项,如两图形重合,应在上边的是第0项。

allID=cv.find_closest(event.x,event.y)  #如halo=3容易找到细直线
if len(allID) > 0:
    clickID=allID[0]
    first_x,first_y = event.x,event.y  

在鼠标左键保持按下并移动事件函数OnMotion中,移动被点击的图形或图像实例,修改坐标first_x,first_y的值。

cv.move(clickID,event.x-first_x,event.y-first_y)
first_x,first_y = event.x,event.y

在鼠标左键抬起事件函数StopMove中,移动被点击的图形图像实例。

cv.move(clickID,event.x-first_x,event.y-first_y)
clickID=-1

完整程序如下:

import tkinter as tk
root = tk.Tk()
root.geometry('300x300')
cv = tk.Canvas(root, height=300, width=300,bg='silver')
cv.pack()
def StartMove(event):
    global first_x,first_y,clickID
    allID=cv.find_closest(event.x,event.y)  #halo =3容易找到细直线
    if len(allID) > 0:
        clickID=allID[0]
        first_x,first_y = event.x,event.y    
def StopMove(event):
    global first_x,first_y,clickID
    cv.move(clickID,event.x-first_x,event.y-first_y)
    clickID=-1    
def OnMotion(event):
    global first_x,first_y,clickID
    if clickID!=-1:
        cv.move(clickID,event.x-first_x,event.y-first_y)
        first_x,first_y = event.x,event.y
clickID=-1
cv.create_line(10, 10, 50, 50, activefill='red')
cv.create_oval(10,70,100,160,activefill='red')
cv.create_rectangle(50,120,150,180,fill='#CCFFFF',activefill='red')
cv.bind("<ButtonPress-1>",StartMove)  #绑定鼠标左键按下事件
cv.bind("<ButtonRelease-1>",StopMove) #绑定鼠标左键松开事件
cv.bind("<B1-Motion>", OnMotion)      #绑定鼠标左键被按下时移动鼠标事件
root.mainloop()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值