You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter 如何实现仅拖动canvas内绘制的多边形而不移动画布

问题根因

你参考的拖动教程是针对独立Tkinter控件(如按钮、Frame)的实现逻辑,而你在Canvas上绘制的多边形属于画布内部图形元素,不是独立控件:

  • 你给图形绑定事件后,触发事件时e.widget返回的是画布对象本身,不是被点击的多边形
  • 你代码里调用的place()方法是用来调整控件位置的,所以实际移动的是整个画布,才会出现全局移动的问题
修复方案

只需要修改两个拖动相关的函数,改用Canvas自带的元素操作接口实现单个图形移动:

  1. 点击时记录起始坐标和当前选中的图形ID
  2. 拖动时计算鼠标偏移量,调用canvas.move()方法仅移动选中的图形
修复后可运行代码
#!/usr/bin/python
import re
import sys
import os
import tkinter as tk

HEIGHT = 1200
WIDTH  = 1600

# 补充原代码缺失的pipeline空实现,避免运行报错
def pipeline(canvas):
    # 你的业务逻辑可在此处实现
    pass

def domain_button(canvas):
    domain  = canvas.create_polygon([420, 100, 420, 100, 420, 175, 420, 175, 380, 175, 380, 120, 420, 120], outline='#000000',fill='#007ECB', width=2, tags="obj1Tag")
    canvas.tag_bind(domain,"<Button-1>", drag_start)
    canvas.tag_bind(domain,"<B1-Motion>", drag_motion)

def button_hover(e):
    button["bg"] = "white"
    status_label.config(text="Get Input")
def button_hover_leave(e):
    button["bg"] = "grey"
    status_label.config(text="")
def button_hover_polygon(label):
    status_label.config(text=label)
def button_hover_polygon_leave(e):
    status_label.config(text="")

# 修改后的拖动起始函数
def drag_start(e):
    canvas = e.widget
    # 记录鼠标起始坐标
    canvas.startX = e.x
    canvas.startY = e.y
    # 获取当前点击的图形元素ID
    canvas.selected_item = canvas.find_closest(e.x, e.y)[0]

# 修改后的拖动逻辑函数
def drag_motion(e):
    canvas = e.widget
    # 计算鼠标偏移量
    dx = e.x - canvas.startX
    dy = e.y - canvas.startY
    # 仅移动选中的图形元素
    canvas.move(canvas.selected_item, dx, dy)
    # 更新起始坐标为当前位置,避免偏移错误
    canvas.startX = e.x
    canvas.startY = e.y


###############Main programme#######################

root = tk.Tk()

canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH, bg='#E7E0E6')
canvas.pack()

frame = tk.Frame(root, bg = '#80c1ff',bd=5)
frame.place(relwidth=1,relheight=1)

###Input box
textBox = tk.Text(frame, font=40)
textBox.place(relx=0.01,rely = 0.05, relwidth=0.4,relheight=0.3)

###Option box
frame2 = tk.Frame(frame, bg = '#D3D3D3')
frame2.place(relx=0.01, rely = 0.45,relheight = 0.35, relwidth = 0.4)
InsertVLDomainButton= tk.Button(frame2,text="insert domain",bg = "grey", command=lambda: domain_button(lower_canvas))
InsertVLDomainButton.place(relx = 0.01, rely = 0.01, relheight = 0.2, relwidth=0.2)


status_label = tk.Label(root, text='test', bd=1)
status_label.place(rely = 0.98, relheight = 0.02, relwidth = 1)

##Big button
button = tk.Button(frame, text = "Go!", bg = "grey", font=40, command=lambda: pipeline(lower_canvas))
button.place(relx=0.1,rely=0.85,relheight=0.1, relwidth=0.2)
button.bind("<Enter>", button_hover)
button.bind("<Leave>", button_hover_leave)

###Results canvas

lower_frame = tk.Frame(root, bg = '#80c1ff', bd=10)
lower_frame.place(relx=0.45, rely=0.05, relwidth=0.55,relheight=0.9)

lower_canvas = tk.Canvas(lower_frame)
lower_canvas.place(relheight=1,relwidth=1)

root.mainloop()

内容的提问来源于stack exchange,提问作者JSJ998

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 09:06:04