如何在 tkinter canvas 中一起移动多个对象?
How to move multiple objects together in tkinter canvas?
我正在尝试使用鼠标拖放在 canvas 周围移动一些带有文本的矩形。我正在使用 find_overlapping 到 select 个要移动的矩形。这意味着最初作为 class 对象 Rect 的一部分创建的文本不会被移动。有没有办法修改我的代码以移动 class 对象中的所有对象或者使用 find_overlapping?
找到 class 对象 ID
矩形上的文本可以相同,如示例所示。用随机标签标记 class 对象中的所有元素以将它们组合在一起是我的第一个想法,但使用 find_ovelapping 检索此类标签信息并未成功。
import tkinter as tk
root=tk.Tk()
PAB=tk.Canvas(width=400, height=400)
#checks if a certain canvas object has a certain tag
def hastag(tag, id):
if any(tag in i for i in PAB.gettags(id)):return True
else:return False
class Rect:
def __init__(self, x1, y1, name):
rec = PAB.create_rectangle(x1,y1,x1+40,y1+40, fill='#c0c0c0', tag=('movable', name))
text = PAB.create_text(x1+20,y1+20, text=name)
#mouse click find object to move
def get_it(event):
delta=5
global cur_rec
for i in PAB.find_overlapping(event.x-delta, event.y-delta, event.x+delta, event.y-delta):
if hastag('movable', i):
cur_rec = i
PAB.bind('<Button-1>', get_it)
#mouse movement moves object
def move_it(event):
xPos, yPos = event.x, event.y
xObject, yObject = PAB.coords(cur_rec)[0],PAB.coords(cur_rec)[1]
PAB.move(cur_rec, xPos-xObject, yPos-yObject)
PAB.bind('<B1-Motion>', move_it)
#test rects
bob = Rect(20,20,'Bob')
rob = Rect(80,80,'Rob')
different_bob = Rect(160,160,'Bob')
PAB.pack()
root.mainloop()
谢谢。如果需要任何说明,我很乐意提供帮助。
这可行,但我不确定这是最好的方法。
基本上它使用了文本被添加到矩形之后的 canvas 的事实,因此可以使用 cur_rec+1
.
来识别它
def move_it(event):
xPos, yPos = event.x, event.y
xObject, yObject = PAB.coords(cur_rec)[0],PAB.coords(cur_rec)[1]
# move rectangle
PAB.move(cur_rec, xPos-xObject, yPos-yObject)
# move text associated with rectangle
PAB.move(cur_rec+1, xPos-xObject, yPos-yObject)
更好的方法是对要一起移动的所有项目使用相同的标签,因此在您的情况下,矩形和文本必须具有相同的标签。
import tkinter as tk
root=tk.Tk()
PAB=tk.Canvas(width=400, height=400, bg="gray")
class Rect:
def __init__(self, x1, y1, name):
tag = f"movable{id(self)}"
rec = PAB.create_rectangle(x1,y1,x1+40,y1+40, fill='#c0c0c0', tag=(tag, ))
text = PAB.create_text(x1+20,y1+20, text=name, tag=(tag,))
def in_bbox(event, item): # checks if the mouse click is inside the item
bbox = PAB.bbox(item)
return bbox[0] < event.x < bbox[2] and bbox[1] < event.y < bbox[3]
#mouse click find object to move
def get_it(event):
delta=5
global cur_rec
cur_rec = PAB.find_closest(event.x, event.y) # returns the closest object
if not in_bbox(event, cur_rec): # if its not in bbox then sets current_rec as None
cur_rec = None
#mouse movement moves object
def move_it(event):
if cur_rec:
xPos, yPos = event.x, event.y
xObject, yObject = PAB.coords(cur_rec)[0],PAB.coords(cur_rec)[1]
PAB.move(PAB.gettags(cur_rec)[0], xPos-xObject, yPos-yObject)
PAB.bind('<Button-1>', get_it)
PAB.bind('<B1-Motion>', move_it)
#test rects
bob = Rect(20,20,'Bob')
rob = Rect(80,80,'Rob')
different_bob = Rect(160,160,'Bob')
PAB.pack()
root.mainloop()
对文本和矩形应用相同的标签。然后,调用move
时使用标签。这是一种方法:
class Rect:
def __init__(self, x1, y1, name):
identifier = f"id:{id(self)}"
rec = PAB.create_rectangle(x1,y1,x1+40,y1+40, fill='#c0c0c0', tags=('movable', name, identifier))
text = PAB.create_text(x1+20,y1+20, text=name, tags=('movable', identifier))
然后您可以 return 标识符而不是所选项目的索引:
def get_it(event):
delta=5
global cur_rec
for i in PAB.find_overlapping(event.x-delta, event.y-delta, event.x+delta, event.y-delta):
if hastag('movable', i):
identifier = [tag for tag in PAB.gettags(i) if tag.startswith("id:")][0]
cur_rec = identifier
我正在尝试使用鼠标拖放在 canvas 周围移动一些带有文本的矩形。我正在使用 find_overlapping 到 select 个要移动的矩形。这意味着最初作为 class 对象 Rect 的一部分创建的文本不会被移动。有没有办法修改我的代码以移动 class 对象中的所有对象或者使用 find_overlapping?
找到 class 对象 ID矩形上的文本可以相同,如示例所示。用随机标签标记 class 对象中的所有元素以将它们组合在一起是我的第一个想法,但使用 find_ovelapping 检索此类标签信息并未成功。
import tkinter as tk
root=tk.Tk()
PAB=tk.Canvas(width=400, height=400)
#checks if a certain canvas object has a certain tag
def hastag(tag, id):
if any(tag in i for i in PAB.gettags(id)):return True
else:return False
class Rect:
def __init__(self, x1, y1, name):
rec = PAB.create_rectangle(x1,y1,x1+40,y1+40, fill='#c0c0c0', tag=('movable', name))
text = PAB.create_text(x1+20,y1+20, text=name)
#mouse click find object to move
def get_it(event):
delta=5
global cur_rec
for i in PAB.find_overlapping(event.x-delta, event.y-delta, event.x+delta, event.y-delta):
if hastag('movable', i):
cur_rec = i
PAB.bind('<Button-1>', get_it)
#mouse movement moves object
def move_it(event):
xPos, yPos = event.x, event.y
xObject, yObject = PAB.coords(cur_rec)[0],PAB.coords(cur_rec)[1]
PAB.move(cur_rec, xPos-xObject, yPos-yObject)
PAB.bind('<B1-Motion>', move_it)
#test rects
bob = Rect(20,20,'Bob')
rob = Rect(80,80,'Rob')
different_bob = Rect(160,160,'Bob')
PAB.pack()
root.mainloop()
谢谢。如果需要任何说明,我很乐意提供帮助。
这可行,但我不确定这是最好的方法。
基本上它使用了文本被添加到矩形之后的 canvas 的事实,因此可以使用 cur_rec+1
.
def move_it(event):
xPos, yPos = event.x, event.y
xObject, yObject = PAB.coords(cur_rec)[0],PAB.coords(cur_rec)[1]
# move rectangle
PAB.move(cur_rec, xPos-xObject, yPos-yObject)
# move text associated with rectangle
PAB.move(cur_rec+1, xPos-xObject, yPos-yObject)
更好的方法是对要一起移动的所有项目使用相同的标签,因此在您的情况下,矩形和文本必须具有相同的标签。
import tkinter as tk
root=tk.Tk()
PAB=tk.Canvas(width=400, height=400, bg="gray")
class Rect:
def __init__(self, x1, y1, name):
tag = f"movable{id(self)}"
rec = PAB.create_rectangle(x1,y1,x1+40,y1+40, fill='#c0c0c0', tag=(tag, ))
text = PAB.create_text(x1+20,y1+20, text=name, tag=(tag,))
def in_bbox(event, item): # checks if the mouse click is inside the item
bbox = PAB.bbox(item)
return bbox[0] < event.x < bbox[2] and bbox[1] < event.y < bbox[3]
#mouse click find object to move
def get_it(event):
delta=5
global cur_rec
cur_rec = PAB.find_closest(event.x, event.y) # returns the closest object
if not in_bbox(event, cur_rec): # if its not in bbox then sets current_rec as None
cur_rec = None
#mouse movement moves object
def move_it(event):
if cur_rec:
xPos, yPos = event.x, event.y
xObject, yObject = PAB.coords(cur_rec)[0],PAB.coords(cur_rec)[1]
PAB.move(PAB.gettags(cur_rec)[0], xPos-xObject, yPos-yObject)
PAB.bind('<Button-1>', get_it)
PAB.bind('<B1-Motion>', move_it)
#test rects
bob = Rect(20,20,'Bob')
rob = Rect(80,80,'Rob')
different_bob = Rect(160,160,'Bob')
PAB.pack()
root.mainloop()
对文本和矩形应用相同的标签。然后,调用move
时使用标签。这是一种方法:
class Rect:
def __init__(self, x1, y1, name):
identifier = f"id:{id(self)}"
rec = PAB.create_rectangle(x1,y1,x1+40,y1+40, fill='#c0c0c0', tags=('movable', name, identifier))
text = PAB.create_text(x1+20,y1+20, text=name, tags=('movable', identifier))
然后您可以 return 标识符而不是所选项目的索引:
def get_it(event):
delta=5
global cur_rec
for i in PAB.find_overlapping(event.x-delta, event.y-delta, event.x+delta, event.y-delta):
if hastag('movable', i):
identifier = [tag for tag in PAB.gettags(i) if tag.startswith("id:")][0]
cur_rec = identifier