简体   繁体   English

如何在 tkinter canvas 中一起移动多个对象?

[英]How to move multiple objects together in tkinter canvas?

Im trying to move some rectangles with text in them around a canvas with mouse dragNdrop.我试图用鼠标拖动 Ndrop 在 canvas 周围移动一些带有文本的矩形。 Im using find_overlapping to select rectangles to be moved.我使用 find_overlapping 到要移动的 select 矩形。 This means the text originally created as part of class object Rect is not moved.这意味着最初作为 class object Rect 的一部分创建的文本不会移动。 Is there a way to modify my code to move all objects in a class object or perhaps find the class object ID using find_overlapping?有没有办法修改我的代码以移动 class object 中的所有对象,或者也许使用 ID_CFDE6331BD46EB2AC96F8911 找到 class ZA8CFDE6331BD46EB2AC96F8911

Text on rectangles can be identical, as shown in example.矩形上的文本可以相同,如示例所示。 Tagging all elements in the class object with a random tag to group them together was my first idea, but retrieving such tag info using find_ovelapping has not been succesful.使用随机标签标记 class object 中的所有元素以将它们组合在一起是我的第一个想法,但使用 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()

Thanks.谢谢。 If any clarifications are neccesary Id be happy to help.如果需要任何澄清,我很乐意提供帮助。

A better way would be to use the same tag for all the items that you want to move together so in your case both rectangle and text must have the same tag.更好的方法是对要一起移动的所有项目使用相同的标签,因此在您的情况下,矩形和文本都必须具有相同的标签。

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()

This will work but I'm not sure it's the best way to do it.这会起作用,但我不确定这是最好的方法。

Basically it uses the fact that the text is added to the canvas after the rectangle so it can be identified using cur_rec+1 .基本上,它使用文本添加到矩形之后的 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)

Apply the same tag to both the text and the rectangle.将相同的标签应用于文本和矩形。 Then, use the tag when calling move .然后,在调用move时使用标签。 Here's one way to do it:这是一种方法:

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))

You can then return the identifier rather than then index of the selected item:然后,您可以返回标识符而不是所选项目的索引:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM