Partage
  • Partager sur Facebook
  • Partager sur Twitter

Remplir un tableau dans la fenêtre Tkinter

Sujet résolu
    4 août 2021 à 9:30:46

    Bonjour,

    Je travaille actuellement sur l'élaboration d'un outil qui servirait à faire l'appel dans une classe.

    L'idée est la suivante :

    Créer un tableau de n Lignes et m Colonnes. La première ligne serait rempli par Jour1, Jour 2, ...., Jour m et la première colonne par Nom1, Nom 2, ..., Nom n.

    Les autres cases seraient des entrées avec un choix sous forme de liste déroulante (Présent, Absent) (combobox).

    J'ai donc conçu le code suivant :

    from tkinter import *
    from tkinter import ttk
    import math
    import numpy as np
    import matplotlib.pyplot as plt
    import pandas as pd
    
    def Selected_elem(event):
        a=Saisie[i][j].get()
        print(a)
        return(a)
    
    
    root = Tk()
    root.title("Présence / abscence")
    root.geometry("1080x720")
    
    frm1 = Frame(root,bg="white",width=1000,height=1000)
    frm1.pack()
    frm1.rowconfigure(0,weight=1)
    frm1.columnconfigure(0,weight=1)
    
    
    Colonne = 10
    Ligne = 5
    Saisie = np.full((11,6),"         ",dtype=object)
    a=" "
    for i in range (Colonne+1):
        Label(frm1,text="  J%s  "%i,borderwidth=1,relief="solid",font=("Arial, 12"),bg="white").grid(column=i,row=0)
    for i in range (Ligne+1):
        Label(frm1,text="  Eleve%s  "%i,borderwidth=1,relief="solid",font=("Arial, 12"),bg="white").grid(column=0,row=i)
    for i in range (1,Colonne+1):
        for j in range (1, Ligne+1):
            Saisie[i][j]=ttk.Combobox(frm1,values=["Absent","Présent"],width=5)
            Saisie[i][j].grid(column=i,row=j)
            Saisie[i][j].bind("<<ComboboxSelected>>", Selected_elem)
            
    root.mainloop()

    J'obtiens bien mon tableau :

    Mais j'ai remarqué que seul la dernière case de celui-ci était prise en compte.
    Pouvez-vous m'aider ?

    Merci d'avance.

    -
    Edité par ThibautDucrocq 4 août 2021 à 9:33:01

    • Partager sur Facebook
    • Partager sur Twitter
      4 août 2021 à 11:08:29

      Bonjour,

      En fin de boucle 

      for i in range (1,Colonne+1):

          for j in range (1, Ligne+1):

      i=10 et j = 5

      Donc dans ta fonction def Selected_elem(event):

      Saisie[i][j] est toujours égal à Saisie[10][5]

      CQFD !

      • Partager sur Facebook
      • Partager sur Twitter
        4 août 2021 à 11:16:38

        Si j'avais un conseil à donner, ça serait d'utiliser la POO et l'héritage de la classe Button.

        Voici un exemple rapide,

        from tkinter import Button, Tk
        
        class MyButton(Button):
        
            buttons = []
        
            def __init__(self, master, **kwargs):
                super().__init__(master, **kwargs)
                MyButton.buttons.append(self)
                self["text"] = f"Button-{len(MyButton.buttons)}"
        
        
        def my_command():
            print(f"Il y a {len(MyButton.buttons)} boutons")
        
        
        
        root = Tk()
        button_1 = MyButton(root, command=my_command)
        button_1.pack()
        button_2 = MyButton(root, command=my_command)
        button_2.pack()
        
        root.mainloop()
        
        from tkinter import Button, Tk
        
        class MyButton(Button):
        
            buttons = []
        
            def __init__(self, master, **kwargs):
                super().__init__(master, **kwargs)
                MyButton.buttons.append(self)
                self["text"] = f"Button-{len(MyButton.buttons)}"
        
        
        def my_command():
            print(f"Il y a {len(MyButton.buttons)} boutons")
        
        
        
        root = Tk()
        for _ in range(10):
            button = MyButton(root, command=my_command)
            button.pack()
        
        print(MyButton.buttons)
        
        root.mainloop()
        




        -
        Edité par fred1599 4 août 2021 à 11:21:11

        • Partager sur Facebook
        • Partager sur Twitter

        Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
        La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

          4 août 2021 à 11:45:26

          Ou bien, tu peux faire ça, ca marche bien :

          def Selected_elem(event,l,c):
          
              a=Saisie[l][c].get()
              print(a)
          
          
          # et ensuite:
          
          for i in range (0,Ligne):
              for j in range (0, Colonne):
                  Saisie[i][j]=ttk.Combobox(fen,values=["Absent","Présent"],width=5)
                  Saisie[i][j].grid(column=j,row=i)
                  Saisie[i][j].bind("<<ComboboxSelected>>", lambda event, l=i, c=j: Selected_elem(event, l, c))



          -
          Edité par Phil_1857 4 août 2021 à 11:46:36

          • Partager sur Facebook
          • Partager sur Twitter
            4 août 2021 à 11:50:08

            Bonjour à vous et merci pour vos réponses.

            Pour Phil_1857 : En effet le problème vient bien du fait qu'il me renvoie le Saisie[10][5]. Mais je ne vois pas comment faire pour avoir les valeurs de chaque case.

            Pour fred1599 : Je vais regarder plus en détail ce que tu as fait. J'ai testé tes programmes et j'essaye de les comprendre. Je n'ai pas encore appris l'utilisation des classes en Python. Je pense que c'est le bon moment pour se plonger dans un tuto ;). 

            Bonne journée à vous !

            • Partager sur Facebook
            • Partager sur Twitter
              4 août 2021 à 11:54:34

              Après faire quelque chose de propre et organisé sans classe c'est possible, suffit juste d'être clair dans sa tête.

              Je partais sur le principe qu'on souhaite changer le comportement, et y ajouter une fonctionnalité de compteur sur les objets créés, mais d'autres solutions existent bien évidemment, peut-être moins techniques mais tout aussi efficaces.

              -
              Edité par fred1599 4 août 2021 à 11:54:48

              • Partager sur Facebook
              • Partager sur Twitter

              Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
              La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

                4 août 2021 à 12:32:52

                la doc de tkinter donne une "astuce" proche (une autre façon de l'écrire en fait) de la solution de Phil_1857: 

                http://tkinter.fdex.eu/doc/event.html#astuce-pour-des-arguments-en-plus-de-evt 

                ccListe = []
                 def creerWidgets():
                    #...
                    for i in range(10):
                        cc = Checkbutton(root, ...)
                        ccList.append(cc)
                        cc.grid(row=1, column=i)
                        def gest(evt, i=i):   1
                            return ccGest(evt, i)
                        cc.bind('<Button-1>', gest)
                    #...
                def ccGest(evt, ccNb):
                    #...



                • Partager sur Facebook
                • Partager sur Twitter
                  4 août 2021 à 12:40:59

                  Merci umfred pour ta réponse, je vais regarder ça.

                  En fait j'ai en partie trouver la solution :

                  from tkinter import *
                  from tkinter import ttk
                  import math
                  import numpy as np
                  import matplotlib.pyplot as plt
                  import pandas as pd
                  
                  
                  def Selected_elem(event):
                      for i in range (1,Colonne+1):
                          for j in range (1,Ligne+1):
                              Saisie[i][j]=Saisie[i][j].get()
                              print(Saisie)
                      return(Saisie)
                              
                              
                  
                  
                  root = Tk()
                  root.title("Présence / abscence")
                  root.geometry("1080x720")
                  
                  frm1 = Frame(root,bg="white",width=1000,height=1000)
                  frm1.pack()
                  frm1.rowconfigure(0,weight=1)
                  frm1.columnconfigure(0,weight=1)
                  
                  
                  Colonne = 10
                  Ligne = 5
                  Saisie = np.full((11,6),"            ", dtype = object)
                  a=" "
                  for i in range (Colonne+1):
                      Label(frm1,text="  J%s  "%i,borderwidth=1,relief="solid",font=("Arial, 12"),bg="white").grid(column=i,row=0)
                      Saisie[i][0]=" J%s "%i
                  for i in range (Ligne+1):
                      Label(frm1,text="  Eleve%s  "%i,borderwidth=1,relief="solid",font=("Arial, 12"),bg="white").grid(column=0,row=i)
                      Saisie[0][i]=" J%s "%i
                  for i in range (1,Colonne+1):
                      for j in range (1, Ligne+1):
                          Saisie[i][j]=StringVar()
                          Saisie[i][j]=ttk.Combobox(frm1,values=["Absent","Présent"],width=5)
                          Saisie[i][j].grid(column=i,row=j)
                          Saisie[i][j].bind("<<ComboboxSelected>>", Selected_elem)
                  
                  root.mainloop()

                  J'ai rajouté une double boucle dans la fonction évènement.

                  Le problème c'est que le changement va fonctionner une fois. Ensuite, ce message d'erreur apparaît :

                  Traceback (most recent call last):

                    File "C:\ProgramData\Miniconda3\envs\py37_v1\lib\tkinter\__init__.py", line 1705, in __call__

                      return self.func(*args)

                    File "T:/DE/Dmta/Travail/Exterieur/Stagiaires/DUCROCQ Thibaut/python/sanstitre0.py", line 18, in Selected_elem

                      Saisie[i][j]=Saisie[i][j].get()

                  AttributeError: 'str' object has no attribute 'get'

                  Je pense que cela doit venir du type de Saisie[i][j] mais je ne vois pas comment le corriger.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    4 août 2021 à 13:10:05

                    la ligne 41 est sans effet, puisqu'à cette ligne, tu dis que c'est une StringVar() et la ligne suivante, c'est un ComboBox

                    Et c'est parce que ligne 12, tu dis que Saisie[i][j] est un string (vu que tu lui affectes la valeur du Combobox) que la prochaine fois, tu ne peux pas l'interroger comme un Combobox et récupérer ensuite sa valeur. Il faut que soit tu ais un tableau des valeurs à côté (une autre variable), soit tu te demandes si tu as vraiment besoin de ce tableau et utiliser directement ton tableau d'objet

                    • Partager sur Facebook
                    • Partager sur Twitter
                      4 août 2021 à 13:24:02

                      Pour Phil_1857 : En effet le problème vient bien du fait qu'il me renvoie le Saisie[10][5]. Mais je ne vois pas comment faire pour avoir les valeurs de chaque case.

                      Thibault, tu n'as pas bien lu ma réponse dans la quelle je proposais une solution qui marche

                      je te la redonne ici, et ca fonctionne parfaitement:

                      La fonction:

                      def Selected_elem(event,l,c):
                      
                          a=Saisie[l][c].get()
                          print(a)



                      Et le bind dans la boucle:

                      Saisie[i][j].bind("<<ComboboxSelected>>", lambda event, l=i, c=j: Selected_elem(event, l, c))



                      • Partager sur Facebook
                      • Partager sur Twitter
                        18 août 2021 à 10:37:28

                        Bonjour,

                        Excusez moi de revenir si tardivement sur ce sujet. Je n'ai pas eu trop le temps de travailler dessus ces 2 dernières semaines.

                        Merci beaucoup Phil pour la commande .bind. J'avais mal compris la notion de lambda event.

                        Maintenant que ça fonctionne, j'ai voulu aller un peu plus loin. Dans la première version de mon petit programme, la taille de mon tableau était fixée. Pour être plus libre, j'ai ajouté 2 entry (nombre de colonne et nombre de ligne) et un bouton qui génère le tableau une fois les données sont entrées.

                        J'aimerai aussi que une fois que le tableau est généré, je puisse modifier ces dimensions sans devoir fermer la fenêtre.
                        Pour agrandir le tableau, il n'y a pas de problème. Pour le rétrécir, ça coince. 

                        Mon code : 

                        from tkinter import *
                        from tkinter import ttk
                        import math
                        import numpy as np
                        import matplotlib.pyplot as plt
                        import pandas as pd
                        
                        def CreerTab1 ():
                            
                            
                            def Selected_elem(event,l,c):
                                a=Saisie[l][c].get()
                                tab1[l][c]=a
                                dataframe = pd.DataFrame(data=tab1)
                                print (tab1)
                                print(dataframe)
                                return(tab1)    
                                
                            frm2.delete('ALL')    
                            Colonne = saisir_Colonne.get()
                            Ligne = saisir_Ligne.get()    
                            tab1 = np.full((Ligne+1,Colonne+1),"            ", dtype = object)
                            LabelFrame(frm2,text="  Eleve  ",borderwidth=1,relief="solid",font=("Arial, 12"),bg="white").grid(column=0,row=0)
                            tab1[0][0]=" Eleve "
                        
                            Saisie = np.full((Ligne+1,Colonne+1),"            ", dtype = object)
                            a=" "
                            for i in range (1,Colonne+1):
                                Label(frm2,text="  J%s  "%i,borderwidth=1,relief="solid",font=("Arial, 12"),bg="white").grid(column=i,row=0)
                                Saisie[0][i]=" J%s "%i
                                tab1[0][i] = "J%s "%i
                            for i in range (1,Ligne+1):
                                Label(frm2,text="  Eleve%s  "%i,borderwidth=1,relief="solid",font=("Arial, 12"),bg="white").grid(column=0,row=i)
                                Saisie[i][0]=" Eleve%s "%i
                                tab1[i][0]="Eleve%s"%i
                                for i in range (1,Ligne+1):
                                    for j in range (1, Colonne+1):
                                        Saisie[i][j]=StringVar()
                                        Saisie[i][j]=ttk.Combobox(frm2,values=["Absent","Présent"],width=5)
                                        Saisie[i][j].grid(column=j,row=i)
                                        Saisie[i][j].bind("<<ComboboxSelected>>", lambda event, l=i, c=j: Selected_elem(event, l, c))
                            
                                    
                        
                        
                        root = Tk()
                        root.title("Présence / abscence")
                        root.geometry("1080x720")
                        
                        frm1 = Frame(root,bg="white",width=1000,height=1000)
                        frm1.pack()
                        frm1.rowconfigure(0,weight=1)
                        frm1.columnconfigure(0,weight=1)
                        
                        Label(frm1,text="Entrez le nombre de colonnes :",font=("Arial,12"),bg="white").grid(column=0,row=0)
                        
                        saisir_Colonne = IntVar()
                        saisir_Colonne.set(0)
                        saisie_Colonne = Entry(frm1,textvariable=saisir_Colonne,width=5,justify = CENTER)
                        saisie_Colonne.grid(column=1,row=0)
                        
                        Label(frm1,text="Entrez le nombre de lignes :",font=("Arial,12"),bg="white").grid(column=0,row=1)
                        
                        saisir_Ligne = IntVar()
                        saisir_Ligne.set(0)
                        saisie_Ligne = Entry(frm1,textvariable=saisir_Ligne,width=5,justify = CENTER)
                        saisie_Ligne.grid(column=1,row=1)
                        
                        frm2 = Canvas(root,bg="white",width=1000,height=1000)
                        frm2.pack()
                        frm2.rowconfigure(0,weight=1)
                        frm2.columnconfigure(0,weight=1)
                        
                        PrintTab1 = Button(frm1,text="Générer Tableau",command=CreerTab1)
                        PrintTab1.grid(column=1,row=4)
                        
                        root.mainloop()

                        Pour arriver à mes fins, j'ai vu sur des forums qu'on pouvait utiliser un canvas au lieu d'un frame et pour supprimer le contenu, utiliser la commande
                        NomDuCanvas.delete("ALL") mais ça ne fonctionne pas.

                        Vous auriez une idée de comment faire ?

                        -
                        Edité par ThibautDucrocq 18 août 2021 à 10:38:28

                        • Partager sur Facebook
                        • Partager sur Twitter
                          18 août 2021 à 13:00:06

                          Bonjour,

                          Pour supprimer le tableau, il faut utiliser la méthode destroy(): 

                          def remove_array():
                          
                              for i in range (0,Ligne):
                                  for j in range (0, Colonne):
                                      Saisie[i][j].destroy()


                          Et en utilisant peu de lignes de code:

                          from tkinter import *
                          from tkinter import ttk
                          
                          def remove_array():
                              global row_nb, column_nb
                          
                              for i in range (0,row_nb):
                                  for j in range (0, column_nb):
                                      input_box[i][j].destroy()
                          
                          def create_array():
                              global row_nb, column_nb
                          
                              row_nb = int(e1.get())
                              column_nb = int(e2.get())
                              
                              for i in range (0,row_nb):
                                  for j in range (0, column_nb):
                                      input_box[i][j]=ttk.Combobox(main_win,values=["Absent","Présent"],width=8)
                                      input_box[i][j].grid(column=j,row=i)
                                      input_box[i][j].bind("<<ComboboxSelected>>", lambda event, l=i, c=j: Selected_elem(event, l, c))
                          
                          def Selected_elem(event,l,c):
                          
                              a=input_box[l][c].get()
                          
                          WIDTH, HEIGHT = 600, 450
                          input_box = [[None for j in range (10)] for i in range (10)]
                          
                          main_win = Tk()
                          main_win.title('Test')
                          main_win.geometry(str(WIDTH)+'x'+str(HEIGHT)+'+300+100')
                          
                          l1 = Label(main_win, text="nb de lignes :")
                          l1.place(x = 10,y = 140)
                          
                          e1 = Entry(main_win, width = 10)
                          e1.place(x = 60,y = 140)
                          e1.focus()
                          
                          l2 = Label(main_win, text="Nb de colonnes :")
                          l2.place(x = 150,y = 140)
                          
                          e2 = Entry(main_win, width = 10)
                          e2.place(x = 220,y = 140)
                          
                          b1 = Button(main_win, text = 'Effacer Tableau', command = remove_array)
                          b1.place(x=10, y=180)
                          
                          b2 = Button(main_win, text = 'Generer Tableau', command = create_array)
                          b2.place(x=150, y=180)
                          
                          main_win.mainloop()



                          -
                          Edité par Phil_1857 19 août 2021 à 11:04:14

                          • Partager sur Facebook
                          • Partager sur Twitter
                            19 août 2021 à 16:12:28

                            Bonjour Phil, merci beaucoup !
                            • Partager sur Facebook
                            • Partager sur Twitter
                              20 août 2021 à 20:38:05

                              ThibautDucrocq a écrit:

                              Bonjour Phil, merci beaucoup !

                              Bonjour,

                              Sujet résolu

                              Tu peux passer le sujet à "résolu" (bouton en haut à droite du sujet) et cliquer sur les pouces levés des messages qui t'ont aidé⋅e ;)

                              • Partager sur Facebook
                              • Partager sur Twitter

                              Remplir un tableau dans la fenêtre Tkinter

                              × 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