Удалить определенный элемент в холсте Tkinter - PullRequest
0 голосов
/ 04 октября 2019

Я использую tkinter для создания ориентированного графа. На этом графике я пытаюсь удалить все созданные стрелки или конкретную.

Это код:

from tkinter import *
import math

class Window:

    #Constructor
    def __init__(self, window, colour="white", width=1000, height=700):
        #Set variables

        self.width = width
        self.height = height
        self.colour = colour
        self.ligacao = []

        #This dictionary is used to keep track of an item being dragged
        self._drag_data = {"x": 0, "y": 0, "item": None}


        #Create canvas
        self.canvas = Canvas(window, bg=self.colour, height=self.height, width=self.width)
        self.canvas.pack()

        #Add bindings for clicking, dragging and releasing overo any object with the "group_drag" tag
        self.canvas.bind("<ButtonPress-1>", self.OnCircleButtonPress)
        self.canvas.bind("<ButtonRelease-1>", self.OnCircleButtonRelease)
        self.canvas.bind("<B1-Motion>", self.OnCircleMotion)


    #This is used to draw particle objects on the canvas, notice the tag that has been added as an attribute
    def _create_circle(self, xcoord, ycoord, r, outline, color, tag):
        self.circle = self.canvas.create_oval(xcoord - r, ycoord - r, xcoord + r, ycoord + r,
                                outline=outline, fill=color, tags=tag)

    #This is used to draw text on top of the object on the canvas
    def _create_text(self, xcoord, ycoord, text, tag):
        self.text = self.canvas.create_text(xcoord, ycoord, text=text, tags=tag)


    def delete_create(self, event):
        self.canvas.delete(self.ligacao)
        self._create_arrow(300, 500, event.x, event.y, 25, "black", "item-20")


    def _create_arrow(self, x0, y0, x1, y1, r, colour, tag):
        delta = math.sqrt(math.pow((y1 - y0), 2) + math.pow((x1 - x0), 2))
        if delta != 0:
            self.arrow = {"x0": x0 + r * (x1 - x0) / delta, "y0": y0 + r * (y1 - y0) / delta,
                         "x1": x1 - r * (x1 - x0) / delta, "y1": y1 - r * (y1 - y0) / delta, "tag": tag}
            self.ligacao.append(self.canvas.create_line(self.arrow["x0"], self.arrow["y0"], self.arrow["x1"], self.arrow["y1"],
                                                fill=colour, arrow=LAST, tags=tag))


        else:
            self.arrow = {"x0": x0, "y0": y0, "x1": x1, "y1": y1, "tag": tag}
            self.ligacao.append(self.canvas.create_line(x0, y0, x1, y1, arrow=LAST, fill=colour, tags=tag))


        return [self.arrow["x0"], self.arrow["y0"], self.arrow["x1"], self.arrow["y1"], self.arrow["tag"]]

    #This uses the find_closest method to get store the x and y positions of the nearest item into the dictionary
    def OnCircleButtonPress(self, event):

        '''Begin drag of an object'''
        # record the item and its location
        item = self.canvas.find_closest(event.x, event.y)[0]
        tags = self.canvas.gettags(item)
        for tag in tags:
            if tag.startswith("item-"):
                break
        #print(tag)
        self._drag_data["item"] = tag
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y

    #This clears the dictionary once the mouse button has been released
    def OnCircleButtonRelease(self, event):
        '''End drag of an object'''

        self.canvas.tag_bind(self.circle, "<ButtonRelease-1>", self.delete_create)
        self.canvas.tag_bind(self.text, "<ButtonRelease-1>", self.delete_create)

        # reset the drag information
        self._drag_data["item"] = None
        self._drag_data["x"] = 0
        self._drag_data["y"] = 0


    #This moves the item as it is being dragged around the screen
    def OnCircleMotion(self, event):
        '''Handle dragging of an object'''
        # compute how much this object has moved
        delta_x = event.x - self._drag_data["x"]
        delta_y = event.y - self._drag_data["y"]
        # move the object the appropriate amount
        self.canvas.move(self._drag_data["item"], delta_x, delta_y)
        # record the new position
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y


class Picture:
#Constructor
    def __init__(self, window):
        self.window = window


    def CircleAndText(self, width=100, height=100, r=50, outline="black", colour="#8BF1F5", text="test", t="item-10"):
        self.window._create_circle(width, height, r, outline, colour, t)
        self.window._create_text(width, height, text, t)


    def ArrowAndText(self, x0, y0, x1, y1, r, colour, text, t="item-20"):
        s = self.window._create_arrow(x0, y0, x1, y1, r, colour, t)
        self.window._create_text(abs(s[0]-s[2])/2 + min(s[0], s[2]),
                                              abs(s[1]-s[3])/2 + min(s[1], s[3]), text, t)

        return s

window = Tk()
window.title("Drag & Drop")

#Create an instance of the window class
main_window = Window(window)

dictionary = {"James": [("Paul", 3), ("Julie", 2), ("Lisa", 1)], "Lisa": [("Paul", 5), ("Antonio", 2)],
        "Fabian": [("George", 2), ("Diana", 4), ("Julie", 5)], "Julie": [("Paul", 2), ("Antonio", 1)], "Antonio": [("Mary", 1), ("Diana", 2)]}


r = 25
x_meio = int(main_window.width/2)
y_meio = int(main_window.height/2)
i = 1
j = 1

circulo = []
texto_circulo = []
tag_seta = []
seta = []
texto_seta = []
tag = []


keys = dictionary.keys()
dictionary_len = len(keys)
angulo = 2 * math.pi / dictionary_len
raio_x = x_meio - r
raio_y = y_meio - r




for name in dictionary:
    k = x_meio + raio_x*math.cos(angulo*(i-1))
    l = y_meio + raio_y*math.sin(angulo*(i-1))
    m = x_meio + raio_x*math.cos(angulo*i)
    n = y_meio + raio_y*math.sin(angulo*i)

    Picture(main_window).CircleAndText(k, l, r, "black", "#8BF1F5", name, "item-%s" % int(i*10))
    Picture(main_window).CircleAndText(k, l, r, "black", "#8BF1F5", name, "item-%s" % int(i*10))
    Picture(main_window).CircleAndText(k, l, r, "black", "#8BF1F5", name, "item-%s" % int(i*10))
    Picture(main_window).ArrowAndText(k, l, m, n, r, "black", name, "item-%s" % int(i * 10))
    Picture(main_window).ArrowAndText(k, l, m, n, r, "black", name, "item-%s" % int(i * 10))

    i += 1

#Start the animation loop
window.mainloop()


Когда я создаю стрелку, создается список self.ligacaoследующим образом:

def _create_arrow(self, x0, y0, x1, y1, r, colour, tag):
        delta = math.sqrt(math.pow((y1 - y0), 2) + math.pow((x1 - x0), 2))
        if delta != 0:
            self.arrow = {"x0": x0 + r * (x1 - x0) / delta, "y0": y0 + r * (y1 - y0) / delta,
                         "x1": x1 - r * (x1 - x0) / delta, "y1": y1 - r * (y1 - y0) / delta, "tag": tag}
            self.ligacao.append(self.canvas.create_line(self.arrow["x0"], self.arrow["y0"], self.arrow["x1"], self.arrow["y1"],
                                                fill=colour, arrow=LAST, tags=tag))


        else:
            self.arrow = {"x0": x0, "y0": y0, "x1": x1, "y1": y1, "tag": tag}
            self.ligacao.append(self.canvas.create_line(x0, y0, x1, y1, arrow=LAST, fill=colour, tags=tag))


        return [self.arrow["x0"], self.arrow["y0"], self.arrow["x1"], self.arrow["y1"], self.arrow["tag"]]

Этот метод используется для удаления одной стрелки и создания другой в новой позиции:

    def delete_create(self, event):
        self.canvas.delete(self.ligacao)
        self._create_arrow(300, 500, event.x, event.y, 25, "black", "item-20")

Когда я использую этот код ниже, я могу удалить толькопоследняя стрелка, освобождая последний кружок или текст, но я хотел бы удалить все стрелки или конкретный, более легкий код, который нужно сделать.

        self.canvas.tag_bind(self.circle, "<ButtonRelease-1>", self.delete_create)
        self.canvas.tag_bind(self.text, "<ButtonRelease-1>", self.delete_create)

Как я могу использовать функцию tag_bind иудалить все стрелки или конкретную?

1 Ответ

0 голосов
/ 04 октября 2019

Самый простой способ удалить все стрелки - дать каждой стрелке как минимум два тега: присвоить ей тег «стрелка», а также тег, уникальный для этой стрелки. Когда вы передаете "arrow" методу delete, он удалит все элементы с этим тегом.

Например, создайте ваши стрелки следующим образом:

def _create_arrow(self, x0, y0, x1, y1, r, colour, tag):
    tags = (tag, "arrow")
    ...
    self.ligacao.append(self.canvas.create_line(..., tags=tags))

Затем удалите все стрелкистановится не более чем self.canvas.delete("arrow")

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...