IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Tkinter Python Discussion :

Tkinter - Python - Canvas - Glisser/déposer de l'extrémité d'une ligne - une question pour les pros [Python 2.X]


Sujet :

Tkinter Python

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Consultant en technologies
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant en technologies

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Par défaut Tkinter - Python - Canvas - Glisser/déposer de l'extrémité d'une ligne - une question pour les pros
    Bonjour à tous,

    Nouveau sur le forum et autodidacte en python, j'ai eut beau écumer le web en français et en anglais, je bloque.
    Ma question est simple et se trouve dans le titre. Voici quelques éléments supplémentaires:
    Faire un glisser/déposer d'un objet "prefa" d'un canevas de type ligne ou ellipse est un point largement documenté sur le web. Or dans mon cas, c'est sur une partie d'un objet que je souhaite agir puisque je souhaite seulement déplacer l'extrémité d'un segment. La méthode "move" ne semble donc pas adaptée et je suppose qu'il faut faire un passpass pour réussir la manip.

    Ceci est un SOS et j'espère que quelqu'un me sorte de son chapeau un moyen détourné pour résoudre mon problème.
    Je m'excuse d'avance si ma biblio est incomplète et que je suis passé à coté d'une solution existante à mon problème.

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 790
    Par défaut
    Salut,

    Citation Envoyé par Last Chance Voir le message
    Or dans mon cas, c'est sur une partie d'un objet que je souhaite agir puisque je souhaite seulement déplacer l'extrémité d'un point. La méthode "move" ne semble donc pas adaptée et je suppose qu'il faut faire un passpass pour réussir la manip.
    Si vous pouviez définir ce que vous entendez par "extrémité d'un point"...
    Mathématiquement, cette chose là n'existe pas.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Consultant en technologies
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant en technologies

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Par défaut
    oups. message corrigé. Je parlais d'une ligne (ou segment) comme dans le titre.

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 790
    Par défaut
    Normalement, vous avez un exemple de code dans cette (vieille) discussion.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Consultant en technologies
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant en technologies

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Normalement, vous avez un exemple de code dans cette (vieille) discussion.

    - W
    Merci wiztricks pour votre réponse. J'ai de quoi étudier mais j'ai peur que cette discussion dépasse de trop loin mon niveau du moment. Je vais étudier ce post en détail et en attendant, pour mettre un peu plus de concret dans ma question, voici un bout de code sans prétention dérivé du bac à sable que l'on trouve un peu partout:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    from Tkinter import *
     
    class test(Canvas): 
        def __init__(self, win, bg="white"):        
            self.canvas = Canvas(win, width=300 ,height=300)        
            self.canvas.create_oval(100, 0, 200, 100, fill='red', tags='t1') 
            self.canvas.create_oval(100, 200, 200, 300, fill='blue', tags='t2') 
            self.canvas.create_line(150, 100, 150, 200, fill='black', tags='t2')
            self.canvas.pack(fill=BOTH,expand=1)
            # 
            self.canvas.bind("<Button-1>", self.mouseDown) 
            self.canvas.bind("<Button1-Motion>", self.mouseMove) 
            self.canvas.bind("<Button1-ButtonRelease>", self.mouseUp)         
     
     
        def mouseDown(self, event): 
            self.canvas.currObject =None 
            self.canvas.x1, self.canvas.y1 = event.x, event.y
            self.canvas.selObject = self.canvas.find_closest(self.canvas.x1, self.canvas.y1) 
            associateTag = self.canvas.gettags(self.canvas.selObject)[0]
            print self.canvas.find_withtag('2')
            self.canvas.selObject = self.canvas.find_withtag(associateTag)
            print self.canvas.selObject
     
        def mouseMove(self, event):  
            x2, y2 = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y) 
            dx, dy = x2 -self.canvas.x1, y2 -self.canvas.y1 
            if self.canvas.selObject:
                for itemInselObject in self.canvas.selObject:
                    self.canvas.move(itemInselObject, dx, dy) 
                    self.canvas.x1, self.canvas.y1 = x2, y2 
     
        def mouseUp(self, event): 
            if self.canvas.selObject: 
                for itemInselObject in self.canvas.selObject:            
                    self.canvas.selObject =None 
     
     
     
    mainWindow = Tk()
    test(mainWindow)
    mainWindow.mainloop()
    alors bien sur, je sais que mon tag du segment est mal-adroit mais pour illustrer, c'est plus simple comme cela.
    Sur la base de ce code, mon objectif est de bouger le cercle bleu et l'extrémité du segment qui lui est initialement attachée MAIS sans que l'autre extrémité (celle liée au cercle rouge) ne bouge.
    J'aurai plaisir à corriger moi même ce code, mais si quelqu'un me précède, ce serait un gain de temps précieux pour moi et cela me permettrait de me focaliser sur des choses moins pointues en programmation pour moi et nettement plus dans mon domaine (la physique des matériaux).

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 790
    Par défaut
    Salut,

    L'idée est "basique".
    On crée un canvas avec une "ligne":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> import Tkinter as tk
    >>> canvas = tk.Canvas()
    >>> canvas.pack()
    >>> line = canvas.create_line(0, 0, 100, 100)
    Si on veut modifier l'extrémité de la ligne, on peut utiliser la méthode ".coords":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> canvas.coords(line, 10, 10, 100, 100)
    []
    Appelée sans "coordonnées", çà retourne leur valeur courante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> canvas.coords(line)
    [10.0, 10.0, 100.0, 100.0]
    Pour bouger l'extrémité "1" là où a clicué la souris, on peut écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> def on_click(x1, y1):
    ...     coords = canvas.coords(line)
    ...     coords[2] = x1
    ...     coords[3] = y1
    ...     canvas.coords(line, *coords)
    ...
    >>> canvas.bind('<1>', lambda e: on_click(e.x, e.y)
    ... )
    '33809832<lambda>'
    >>>
    Et voilà. Pour le reste, je ne vous gâcherai pas le plaisir d'intégrer cela dans votre code

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Consultant en technologies
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant en technologies

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Salut,

    L'idée est "basique".
    On crée un canvas avec une "ligne":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> import Tkinter as tk
    >>> canvas = tk.Canvas()
    >>> canvas.pack()
    >>> line = canvas.create_line(0, 0, 100, 100)
    Si on veut modifier l'extrémité de la ligne, on peut utiliser la méthode ".coords":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> canvas.coords(line, 10, 10, 100, 100)
    []
    Appelée sans "coordonnées", çà retourne leur valeur courante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> canvas.coords(line)
    [10.0, 10.0, 100.0, 100.0]
    Pour bouger l'extrémité "1" là où a clicué la souris, on peut écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> def on_click(x1, y1):
    ...     coords = canvas.coords(line)
    ...     coords[2] = x1
    ...     coords[3] = y1
    ...     canvas.coords(line, *coords)
    ...
    >>> canvas.bind('<1>', lambda e: on_click(e.x, e.y)
    ... )
    '33809832<lambda>'
    >>>
    Et voilà. Pour le reste, je ne vous gâcherai pas le plaisir d'intégrer cela dans votre code

    - W
    Il parait qu'il n'y a pas de question bête. Ca n'empêche que l'on peut se trouver bête à l'arrivée de la réponse.... Merci beaucoup Wiztricks. Je corrigerai mon exemple au cas où ça puisse servir à quelqu'un.

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Consultant en technologies
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant en technologies

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Par défaut
    Alors voilà, Je n'empêcherai pas un puriste de critiquer, alléger ou réécrire ce code (ce sera même avec plaisir ).
    Pour les autres, voilà un truc qui fonctionne.
    WARNING: je ne suis pas une référence et ces quelques lignes sont surement pleines de chose à ne pas faire. A bon entendeur....

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    from Tkinter import *
     
    class test(Canvas): 
        def __init__(self, win, bg="white"):        
            self.canvas = Canvas(win, width=500 ,height=500)        
            self.canvas.create_oval(100, 0, 200, 100, fill='red', tags='t1') 
            self.canvas.create_oval(100, 200, 200, 300, fill='blue', tags='t2') 
            self.canvas.create_oval(300, 0, 400, 100, fill='green', tags='t3') 
            self.canvas.create_line(150, 100, 150, 200, fill='black', tags=('t2','t1'))
            self.canvas.create_line(350, 100, 150, 200, fill='black', tags=('t3','t2'))
            self.canvas.pack(fill=BOTH,expand=1)
            # 
            self.canvas.bind("<Button-1>", self.mouseDown) 
            self.canvas.bind("<Button1-Motion>", self.mouseMove) 
            self.canvas.bind("<Button1-ButtonRelease>", self.mouseUp)         
     
     
        def mouseDown(self, event):
            self.foundPoint = 0
            self.canvas.currObject =None 
            self.canvas.x1, self.canvas.y1 = event.x, event.y
            self.canvas.selObject = self.canvas.find_closest(self.canvas.x1, self.canvas.y1) 
            associateTag = self.canvas.gettags(self.canvas.selObject)[0]
            print self.canvas.find_withtag('2')
            self.canvas.selObject = self.canvas.find_withtag(associateTag)
            print self.canvas.selObject
     
        def mouseMove(self, event):
            x1, y1 = self.canvas.x1 , self.canvas.y1
            x2, y2 = self.canvas.canvasx(event.x), self.canvas.canvasy(event.y) 
            dx, dy = x2 - x1 , y2 - y1 
            if self.canvas.selObject:
                for itemInselObject in self.canvas.selObject:
                    if self.canvas.type(itemInselObject)=='line':
                        coords = self.canvas.coords(str(itemInselObject))
                        if self.foundPoint == 0:   
                            print 'ici'
                            print self.foundPoint
                            tmp1 = (x1-coords[0])*(x1-coords[0]) + (y1-coords[1])*(y1-coords[1])
                            tmp2 = (x1-coords[2])*(x1-coords[2]) + (y1-coords[3])*(y1-coords[3])
                            if tmp1 < tmp2:
                                self.pt = 0              
                            else:
                                self.pt = 1
                            self.foundPoint = 1
                        print self.foundPoint
                        print 'la'
                        coords[2*self.pt] = coords[2*self.pt] + dx
                        coords[2*self.pt+1] = coords[2*self.pt+1] + dy
                        self.canvas.coords(str(itemInselObject), *coords)
                    else:
                        self.canvas.move(itemInselObject, dx, dy) 
                        self.canvas.x1, self.canvas.y1 = x2, y2 
     
        def mouseUp(self, event):
            if self.canvas.selObject: 
                for itemInselObject in self.canvas.selObject:            
                    self.canvas.selObject =None 
     
     
     
    mainWindow = Tk()
    test(mainWindow)
    mainWindow.mainloop()
    Merci encore à Wiz

  9. #9
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 790
    Par défaut
    Salut,

    Si on veut "illustrer" ce que le Canvas Tk et Python mettent à notre disposition pour faire cela, j'écrirai plutôt la chose ainsi.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    import Tkinter as tk
     
    class Node:
        _instances = {}
     
        @classmethod
        def create(cls, x, y, radius=25, color='grey'):
            node = Node(x, y, radius, color)
            cls._instances[node.iid] = node
            return node
     
        @classmethod
        def get(cls, iid):
            return cls._instances.get(iid, None)
     
        def __init__(self, x, y, radius, color):
            x0, y0, x1, y1 = x - radius, y - radius, x+radius, y+radius
            self.iid = canvas.create_oval(
                            x0, y0, x1, y1, 
                            fill=color, 
                            tags='node', 
                            activeoutline='green',
                            activewidth=3)
            self.center = x, y
            self.radius = radius
            self.edges = []
     
        def add_edge(self, node):
           x0, y0 = self.center
           x1, y1 = node.center
           iid = canvas.create_line(x0, y0, x1, y1, tags='edge')
           canvas.lower(iid, 'node')
           self.edges.append(iid)
           node.edges.append(iid)
     
        def moveto(self, x, y):
            cx, cy = self.center
            for iid in self.edges:
                x0, y0, x1, y1 = canvas.coords(iid)
                if (cx, cy) == (x0, y0):
                    coords = x, y, x1, y1
                elif (cx, cy) == (x1, y1):
                    coords = x0, y0, x, y
                else:
                    raise ValueError('center mismatch with edge coords')
                canvas.coords(iid, *coords)
            canvas.move(self.iid, x - cx, y - cy)
            self.center = x, y
     
    bound_function = None
    def on_b1_press(event):
        global bound_function
        iid = canvas.find_withtag('current')[0]
        node = Node.get(iid)
        bound_function = canvas.bind('<Motion>', lambda e: node.moveto(e.x, e.y))  
     
     
    def on_b1_release(event):
        global bound_function
        if bound_function:
            canvas.unbind('<Motion>', bound_function)
            bound_function = None
     
    if __name__ == '__main__':
        root = tk.Tk()
     
        canvas = tk.Canvas(width=500, height=500)
        canvas.pack(fill='both', expand=1)
        canvas.tag_bind('node', '<ButtonPress-1>', on_b1_press)
        canvas.tag_bind('node', '<ButtonRelease-1>', on_b1_release)
     
        n0 = Node.create(150, 50, color='red')
        n1 = Node.create(150, 250, color='blue')
        n2 = Node.create(350, 50, color='green')
     
        n0.add_edge(n1)
        n2.add_edge(n1)
     
        tk.mainloop()
    Puisqu'on déplace les nœuds d'une sorte de graphe, j'ai pris le parti d'organiser mon code autour d'une class "Node" contenant des "edges".
    C'est (à mon sens) le seul objet qui mérite une classe pour "simplifier" l'ensemble du code.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Consultant en technologies
    Inscrit en
    Novembre 2014
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant en technologies

    Informations forums :
    Inscription : Novembre 2014
    Messages : 7
    Par défaut
    C'est en effet sans comparaison. Très élégant. Super Wiz et merci encore. (PS: je vous ai envoyé un MP mais je ne sais pas si ça a bien fonctionné...)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Glisser-déposer avec Tkinter? (Tkdnd?)
    Par tyrtamos dans le forum Tkinter
    Réponses: 2
    Dernier message: 17/07/2008, 10h53
  2. Listes Simples et propriétés / Glisser déposer
    Par MeRc|LeSs dans le forum VB 6 et antérieur
    Réponses: 12
    Dernier message: 04/12/2005, 00h14
  3. Paramétrage du glisser-déposer selon l'application cible
    Par annedeblois dans le forum Windows
    Réponses: 3
    Dernier message: 17/10/2005, 22h57
  4. Glisser déposer sur formulaire
    Par norvel dans le forum Access
    Réponses: 5
    Dernier message: 03/10/2005, 12h20
  5. [MFC] Glisser/Déposer dans une CView
    Par octopus984 dans le forum MFC
    Réponses: 2
    Dernier message: 26/04/2005, 11h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo