Partage
  • Partager sur Facebook
  • Partager sur Twitter

Tkinter-grid évent clic bouton renvoie (x,y)bouton

Sujet résolu
    19 janvier 2019 à 16:26:33

    Bonjour pour un programme sur python,

    Quand l'événement d'un clique gauche de la souris sur un bouton est détecté, j'active une fonction

    J'aimerais que cette fonction m'affiche les coordonnées x et y sur la grille (avec .grid) du bouton sélectionné mais je n'y arrive pas

    J'ai une grille de 7 colonnes (allant de 0 à 6) et de 7 lignes (allant de 0 à 6)

    Pouvez-vous m'aider s'il vous plaît ?

    def clic(event):
    
        print("Vous avez cliqué sur le bouton de coordonnées X =" + str(coordonnée x du bouton) +", Y =" + str(coordonnée y du bouton))
    
    Fenetre.bind_class("Button","<Button-1>", clic)

    (il faut échanger "coordonnée x du bouton" et "coordonnée y du bouton" par une fonction permettant d'obtenir cette coordonnée)

    Exemple de coordonnées du bouton : (4,5) ce qui équivaut à : (ligne 4, colonne 5)

    -
    Edité par SébastienBacoup 19 janvier 2019 à 17:18:43

    • Partager sur Facebook
    • Partager sur Twitter
      19 janvier 2019 à 16:53:27

      Ceci fait ce que tu veux ? (attention ça fonctionne avec le clic droit)
      from tkinter import *
      
      fenetre = Tk()
      
      
      def clic(event):
          xb = str(event.x)
          yb = str(event.y)
          print("Vous avez cliqué sur le bouton de coordonnées X =" + str(xb) + ", Y =" + str(yb))
      
      
      fenetre.bind("<Button-3>", clic)
      
      
      fenetre.mainloop()

      -
      Edité par Blue_Badger 19 janvier 2019 à 16:55:39

      • Partager sur Facebook
      • Partager sur Twitter
        19 janvier 2019 à 17:13:24

        Avec ça j'obtient les coordonnées de mon curseur

        Moi j'ai besoin des coordonnées du bouton sur lequel j'ai cliqué avec ma souris

        Bouton positionné sur une grille avec .grid

        J'ai une grille de 7 colonnes (allant de 0 à 6) et de 7 lignes (allant de 0 à 6)

        Je veux obtenir les coordonnées du bouton sur lequel j'ai cliqué dans cette grille

        -
        Edité par SébastienBacoup 19 janvier 2019 à 17:17:31

        • Partager sur Facebook
        • Partager sur Twitter
          19 janvier 2019 à 17:24:57

          désolé j'avais mal compris.

          Du coup puisque tu a des boutons ne peut tu pas créer une fonction vers la quelle les boutons renverrais et qui prendrais en argument les coordonnées, comme ceci:

          from tkinter import *
          
          fenetre = Tk()
          
          
          def clic(x, y):
          
              print("Vous avez cliqué sur le bouton de coordonnées X =" + str(x) + ", Y =" + str(y))
          
          
          Button(text="a", command=lambda: clic(1, 1)).grid(row=1, column=1)
          Button(text="a", command=lambda: clic(1, 2)).grid(row=1, column=2)
          Button(text="a", command=lambda: clic(2, 1)).grid(row=2, column=1)
          Button(text="a", command=lambda: clic(2, 2)).grid(row=2, column=2)
          
          fenetre.mainloop()
          

          -
          Edité par Blue_Badger 19 janvier 2019 à 17:34:12

          • Partager sur Facebook
          • Partager sur Twitter
            19 janvier 2019 à 17:35:19

            Le problème c'est que je dois faire ça pour tous mes boutons (total de 33) et 33 lignes juste pour ça fait beaucoup, ceci-dit je vais peut-être faire ça même si c'est moins bien écrit parce que ça devrait fonctionner

            -
            Edité par SébastienBacoup 19 janvier 2019 à 17:37:23

            • Partager sur Facebook
            • Partager sur Twitter
              19 janvier 2019 à 17:40:12

              Oui je suis bien d'accord c'est très moche mais pour l'instant c'est le seul truc qui me vient.

              Je vais continuer à y réfléchir.

              • Partager sur Facebook
              • Partager sur Twitter
                19 janvier 2019 à 17:41:55

                A quoi que ! Je crois que je suis juste bête, je peux rajouter ta solution dans ma boucle "for" qui me permet en quelques lignes de faire le même boulot que 33 lignes
                • Partager sur Facebook
                • Partager sur Twitter
                  19 janvier 2019 à 17:44:28

                  J'allais te demander si tu créais tes boutons avec une boucle ...:lol:

                  Dit moi si ça marche.

                  -
                  Edité par Blue_Badger 19 janvier 2019 à 17:44:43

                  • Partager sur Facebook
                  • Partager sur Twitter
                    19 janvier 2019 à 17:54:49

                    Pour ma boucle, mon problème est que x et y (le nom des variable) est le même nom pour les 33 boutons et il ne garde pas en mémoire les variables "x" et "y" du moment de leur attribution mais les variables "x" et "y" finales ainsi, d'après la fonction tous mes boutons sont de coordonnées (4,6) -> la coordonnée de mon dernier bouton x)

                    Un moyen pour rendre inchangeable les valeurs entrées dans la fonction lambda?

                    • Partager sur Facebook
                    • Partager sur Twitter
                      19 janvier 2019 à 17:57:38

                      J'ais du mal à visualiser le problème, tu peut poster ton code ?
                      • Partager sur Facebook
                      • Partager sur Twitter
                        19 janvier 2019 à 17:58:20

                        from tkinter import *
                        Fenetre=Tk()
                        
                        def clic(x,y):
                            print("Vous avez cliqué sur le bouton de coordonnées X =" + str(x) + ", Y =" + str(y))
                        
                        #Variable images
                        case_pion=PhotoImage(file="case_pion.gif")
                        case_vide=PhotoImage(file="case_vide.gif")
                        case_verte=PhotoImage(file="case_verte.gif")
                        
                        #Création des cases
                        dictionnaire={}
                        for i in range (49):
                            a=i//7
                            b=i-7*(i//7)
                            if a<2 and b<2 or a<2 and b>4 or a>4 and b<2 or a>4 and b>4:
                                continue
                            else:
                                dictionnaire[a,b]="pion"
                            dictionnaire[3,3]="case_vide"
                        
                        #Mise en place du plateau
                        for cle in dictionnaire.keys():
                            (a,b)=cle
                            x="a"
                            y="b"
                            if dictionnaire[cle]=="pion":
                                cle=Button(Fenetre, image=case_pion, command=lambda: clic(x,y)).grid(row=a,column=b)
                            else:
                                cle=Button(Fenetre, image=case_vide, command=lambda: clic(x,y)).grid(row=a,column=b)
                            
                        Fenetre.mainloop()

                        https://pmcdn.priceminister.com/photo/solitaire-d-23-5-plateau-verre-1137798208_L.jpg

                        C'est à ça que ressemble mon programme, je compte utiliser un dictionnaire pour enregistrer chaque point (coordonnées + pion ou case vide)

                        Tout ce qu'il me manque pour terminer mon programme c'est de récupérer les coordonnées du bouton cliqué, le reste je sais comment faire

                        -
                        Edité par SébastienBacoup 19 janvier 2019 à 17:59:09

                        • Partager sur Facebook
                        • Partager sur Twitter
                          19 janvier 2019 à 19:55:06

                          Désolé pour l'interruption, je te conseille d'utiliser une classe

                          from tkinter import * # 
                          
                          fenetre = Tk() # création de la fenetre avec tkinter bon ça tu la sait surement 
                          
                          
                          class ButtonOfTheGrid: # declaration de la classe
                          
                              def __init__(self, x, y): # définition du constructeure de la classe
                          
                                  self.x = x # on crée une variable interne à la classe qui prend pour valeur le x 
                                              # passé en argument
                                  self.y = y # pareille pour y
                          
                                  Button(text="a", command=self.clic).grid(row=self.x, column=self.y) # on crée un bouton avec une méthode de la classe comme command
                                                                                                       # et on affiche se bouton avec "grid", et on passe à grid les 
                                                                                                       # x et y reçut en argument à la création de l'objet.
                          
                              def clic(self): # on définit la méthode clic
                          
                                  print("Vous avez cliqué sur le bouton de coordonnées X =" + str(self.x) + ", Y =" + str(self.y)) # simple print des x et y reçut en argument
                          
                          
                          for i in range(9): # boucle qui génère des objet "ButtonOfTheGrid" 
                              # ici je crée un carré 3*3 il faut adapter les condtions en fonction de la "forme" que tu veux 
                              if i - 6 >= 0:
                                  ButtonOfTheGrid(int(i/3), i - 6) # le "int" permet de tronquer des nombres non entiers
                              elif i - 3 >= 0:
                                  ButtonOfTheGrid(int(i/3), i - 3)
                              else:
                                  ButtonOfTheGrid(int(i/3), i)
                          
                          fenetre.mainloop()

                          -
                          Edité par Blue_Badger 20 janvier 2019 à 15:33:32

                          • Partager sur Facebook
                          • Partager sur Twitter
                            19 janvier 2019 à 21:20:02

                            Salut,

                            je pense aussi que le plus judicieux serais l'utilisation d'une classe, comme le dit Anneziboulonnette. Mais à mon avis, une solution comme celle-ci serait préférable :

                            import tkinter as tk
                            
                            
                            class GridButton(tk.Button):
                                def __init__(self, *args, **kwargs):
                                    if 'command' in kwargs:
                                        kwargs['command'] = self._wrap_command(kwargs['command'])
                                    super().__init__(*args, **kwargs)
                                    self.column = 0
                                    self.row = 0
                                    
                                def grid(self, *args, **kwargs):
                                    super().grid(*args, **kwargs)
                                    self.column = kwargs.get('column', 0)
                                    self.row = kwargs.get('row', 0)
                            
                                def configure(self, *args, **kwargs):
                                    if 'command' in kwargs:
                                        kwargs['command'] = self._wrap_command(kwargs['command'])
                                    super().configure(*args, **kwargs)
                                config = configure
                            
                                def _wrap_command(self, command):
                                    def wrapper():
                                        command(self)
                                    return wrapper
                            
                            # Pour tester la classe GridButton :
                            
                            def onclick(btn):
                                print(btn.row, btn.column)
                            
                            root = tk.Tk()
                            GridButton(root, text='1 1', command=onclick).grid(row=1, column=1)
                            GridButton(root, text='2 2', command=onclick).grid(row=2, column=2)
                            GridButton(root, text='1 3', command=onclick).grid(row=1, column=3)
                            GridButton(root, text='2 4', command=onclick).grid(row=2, column=4)
                            root.mainloop()
                            



                            la classe s'utilise exactement comme tkinter.Button, sauf que le callback onclick doit prendre 1 argument : le bouton sur lequel on a cliqué. Cet argument est passé automatiquement, pas besoin de ton soucier. Après, ce n'est pas parfait non plus : si aucun argument n'est passé a grid, row et column vaudrons 0 pas defaut. (La classe peut paraitre compliquée au premier abord, demande moi si tu veux plus de précisions.)

                            (EDIT: correction d'un petit bug)

                            -
                            Edité par __Nicolas__ 19 janvier 2019 à 21:26:38

                            • Partager sur Facebook
                            • Partager sur Twitter
                              20 janvier 2019 à 11:30:53

                              __Nicolas__ a écrit:

                               Mais à mon avis, une solution comme celle-ci serait préférable :


                              Pourquoi préférable, c'est quand même beaucoup plus long non ?

                              tu peut m'expliquer s'il te plait ?

                              (au passage j'ais modifié ma proposition pour qu'elle affiche un carré de boutons de 3*3)

                              • Partager sur Facebook
                              • Partager sur Twitter
                                20 janvier 2019 à 11:53:09

                                Pfiou, désolé pour l'attente j'ai été faire pas mal de recherche pour essayer de comprendre ce foutu super() et en apprendre plus sur "self" que l'on peut d'ailleurs remplacer par n'importe quel nom de variable mais qui est une convention utilisée à peu près partout apparemment.

                                Bref, pour la solution de Nicolas, tes boutons me conviennent parfaitement mais je n'arrive pas à expliquer leur fonctionnement, j'ai bien compris que :

                                class GridButton(tk.Button):
                                def __init__(self*args, **kwargs):
                                if 'command' in kwargs:
                                kwargs['command'= self._wrap_command(kwargs['command'])
                                super().__init__(*args, **kwargs)
                                self.column = 0
                                self.row = 0
                                def grid(self*args, **kwargs):
                                super().grid(*args, **kwargs)
                                self.column = kwargs.get('column'0)
                                self.row = kwargs.get('row'0)
                                def configure(self*args, **kwargs):
                                if 'command' in kwargs:
                                kwargs['command'= self._wrap_command(kwargs['command'])
                                super().configure(*args, **kwargs)
                                config = configure
                                def _wrap_command(self, command):
                                def wrapper():
                                command(self)
                                return wrapper

                                Toutes ces lignes de codes, c'est pour créer cette classe GridButton (que l'on pourrait nommer différemment) mais je ne les comprend pas

                                Sinon la solution d'Annezibou Lonnette me paraît parfaite, courte et bien plus simple

                                Pourrais-tu cependant m'expliquer chacune de les lignes une par une :

                                class ButtonOfTheGrid:
                                def __init__(self, x, y):
                                self.x = x
                                self.y = y
                                Button(text="a", command=self.clic).grid(row=self.x, column=self.y)

                                Je pense les avoir comprises mais je préfère être sûr car je vais devoir les expliquer un jour ^^

                                -
                                Edité par SébastienBacoup 20 janvier 2019 à 12:08:42

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  20 janvier 2019 à 15:31:24

                                  Voila j'ais commenté mon code, j'aurais du mal à faire mieux comme explication, je suis encore débutant:)

                                  sinon si il reste des trucs pas claire tu peut peut être aller voire le coure sur les classes ici

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    20 janvier 2019 à 15:51:25

                                    Anneziboulonnette a écrit:

                                    Pourquoi préférable, c'est quand même beaucoup plus long non ?

                                    tu peut m'expliquer s'il te plait ?


                                    La classe est plus longue bien sûr, mais à mon sens c'est plus "pythonnique".

                                    La classe hérite de tkinter.Button, et globalement, quand on fait de la poo avec tkinter, c'est comme ça qu'il faut faire. Du coup son fonctionnement est exactement similaire au bouton de base, on peut plus facilement passer des arguments à l'initialisation, définir(/redéfinir) le callback onclic, reconfigurer le boutton, le grid/ungrid... Bref, tout ce qu'on pourrait avoir besoin de faire quand on programme avec tk.

                                    SébastienBacoup a écrit:

                                    Pfiou, désolé pour l'attente j'ai été faire pas mal de recherche pour essayer de comprendre ce foutu super() et en apprendre plus sur "self" que l'on peut d'ailleurs remplacer par n'importe quel nom de variable mais qui est une convention utilisée à peu près partout apparemment.

                                    Bref, pour la solution de Nicolas, tes boutons me conviennent parfaitement mais je n'arrive pas à expliquer leur fonctionnement, j'ai bien compris que :

                                    class GridButton(tk.Button):
                                    def __init__(self*args, **kwargs):
                                    if 'command' in kwargs:
                                    kwargs['command'= self._wrap_command(kwargs['command'])
                                    super().__init__(*args, **kwargs)
                                    self.column = 0
                                    self.row = 0
                                    def grid(self*args, **kwargs):
                                    super().grid(*args, **kwargs)
                                    self.column = kwargs.get('column'0)
                                    self.row = kwargs.get('row'0)
                                    def configure(self*args, **kwargs):
                                    if 'command' in kwargs:
                                    kwargs['command'= self._wrap_command(kwargs['command'])
                                    super().configure(*args, **kwargs)
                                    config = configure
                                    def _wrap_command(self, command):
                                    def wrapper():
                                    command(self)
                                    return wrapper

                                    Toutes ces lignes de codes, c'est pour créer cette classe GridButton (que l'on pourrait nommer différemment) mais je ne les comprend pas

                                    Effectivement, si tu n'a jamais touché à la programmation orienté objet, ça risque d'être très difficile à comprendre, donc je ne vais pas m'aventurer à expliquer le fonctionnement. Du coup si tu ne comprend pas comment ça marche je ne conseil pas de l'utiliser, surtout si c'est un travail à présenter ensuite.

                                    Par contre, si tu as un peu de temps et de motivation, je te conseillerais de commencer à te familiariser avec le concept de poo : c'est très intéressant (et un peu utile aussi, si tu veux t'aventurer dans des programmes plus complexes plus tard).

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      20 janvier 2019 à 22:09:45

                                      Bon bas, j'ai bien l'impression que mon problème est résolu, un grand merci à Anneziboulonnette, j'ai juste à retoucher un peu tes boutons pour qu'ils me conviennent parfaitement, ça m'a réglé mon problème et je ne pense pas tomber sur un nouveau problème par la suite.

                                      Je vais pouvoir finir mon Solitaire pour mon projet d'ISN ^^ (oui je sais on a jusqu'à la fin de l'année mais j'adore ça)

                                      Sinon merci aussi à __Nicolas__ tes boutons sont peut-être plus optimisés, je ne sais pas, je n'ais pas les connaissances pour juger ça mais en tout cas leur fonctionnement reste un peu trop compliqué pour moi, je crois avoir compris au moins la moitié de ton code mais comme je vais devoir présenter ça, je vais rester sur la solution d'Anneziboulonnette, qui est bien plus simple

                                      -
                                      Edité par SébastienBacoup 20 janvier 2019 à 22:11:46

                                      • Partager sur Facebook
                                      • Partager sur Twitter

                                      Tkinter-grid évent clic bouton renvoie (x,y)bouton

                                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                      • Editeur
                                      • Markdown