Déplacer un objet graphique tkinter

Déplacer un objet graphique tkinter #

On place 6 objets (cercles avec label) dans un canvas tkinter et on souhaite que l’utilisateur puisse les déplacer à la souris par drag and drop.

L’idée générale est d’associer des /tags/ tkinter aux objets. On peut ensuite déplace les objets par tag. Si deux objets ont le même tag, ils sont déplacée en même temps (le cercle et le label).

#!/usr/bin/env python3
import tkinter as tk

class Fenetre(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        self.pack(fill='both', expand=1)        
        self.canvas = tk.Canvas(self, width=500, height=500, background="#383")
        self.canvas.pack(padx=8, pady=8) 
        self.create_drawing()

    def move(self, event):
        def node_center(tag):
            """ Renvoie le centre du noeud étant donné
                son rectangle englobant
            """
            x1, y1, x2, y2 = self.canvas.coords(tag)
            return (x1 + x2) // 2, (y1 + y2) // 2
        # ---------------------------------------------------------------------
        x, y = event.x, event.y # Coordonnées cliquées
        tags = self.canvas.gettags(tk.CURRENT) # tags contient le tag "node-B" et "current"

        for tag in tags:
            if not tag.startswith("node"):
                continue
            # Ceci est normalement effectué pour un seul tag (par ex "node-B").
            # Comme deux objets ont ce tag, les deux sont déplacés simultanément
            # par self.canvas.move...
            x1, y1 = node_center(tag)
            self.canvas.move(tag, x-x1, y-y1) 

    def create_drawing(self):
        # Affichage des noeuds et du texte
        nodes = [("A", 100, 200), ("B", 50, 100), ("C", 400, 20)]
        for nodename, nodex, nodey in nodes:
            tmpnode = self.canvas.create_oval(nodex - 10, nodey - 10, 
                                              nodex + 10, nodey + 10, 
                                              fill="#000066", outline="#0000ff")
            tmptxt = self.canvas.create_text(nodex, nodey, fill="#ffffff", text=nodename)
            tag = "node-{}".format(nodename)
            self.canvas.addtag_withtag(tag, tmpnode) # On tague les objets avec : "node-A", "node-B"...
            self.canvas.addtag_withtag(tag, tmptxt)
            #Association callbacks au rond ET au texte
            self.canvas.tag_bind(tmpnode, '<B1-Motion>', self.move)
            self.canvas.tag_bind(tmptxt, '<B1-Motion>', self.move)

root, gui = None, None
# Création de l'application
root = tk.Tk()
# Ajout des éléments graphiques 
gui = Fenetre(root)
# Boucle des événements
root.mainloop()