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 :

Modification d'une variable avec un bouton TKinter [Python 3.X]


Sujet :

Tkinter Python

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Points : 30
    Points
    30
    Par défaut Modification d'une variable avec un bouton TKinter
    Bonjour

    Merci pour le temps que vous passez à lire les messages des débutants comme moi. :-)

    Je suis en train de commencer à apprendre à programmer en Python. Mon projet actuel est assez simple :
    créer une fenêtre qui va afficher des "cartes flashs" correspondant à des listes. Des boutons serviront pour passer à la carte précédente ou suivante. (Je suis professeur en école primaire et ça me servirait comme application d'apprentissage)

    J'ai commencé à utiliser les "class" (Ce qui me procura un grand plaisir quand ça fonctionna pour la première fois :-D )
    Cependant, je suis bloqué sur l'action des boutons.

    J'ai créé une fonction qui devrait être activée par une pression sur le bouton, mais rien ne se passe...
    • Ou la variable "i" n'évolue pas comme je l'imagine (elle ne bouge pas), mais je ne sais pas encore utiliser un débogueur pour observer ça...
    • Ou c'est la fenêtre qui ne se rafraîchit pas, et donc qui ne prend pas en compte l'évolution de ma variable "i".

    Je penche plus vers la seconde hypothèse, mais on ne sait jamais...

    Voici mon code. Pourriez-vous m'orienter ?

    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
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
     
    # Création d'une fenetre pour afficher les flash cards affichant une image et 4 informations
    # en utilisant les objets
    # Tutoriel sur les objets : https://www.youtube.com/watch?v=dfUM_9xibf8
    # Import de la bibliothèque TKinter
    from tkinter import *
     
    ########################
    #    Partie logique    #
    ########################
     
    # Création d'une "classe" contenant les information d'une "flash card"
    class FlashCard:
     
        def __init__(self, num, pers, act, obj):   # Constructeur de classe
            self.num = num          # Création d'un nouvel attribut qui se verra affecter la valeur de la variable
            self.pers = pers
            self.act = act
            self.obj = obj
            # self.img = img        # Pour plus tard
     
        def get_num(self):          # Création d'une méthode (fonction dans une classe) "Geter" ou "Assesseur" dans ce cas, pour récupérer une info
            return self.num
     
        def get_pers(self):
            return self.pers
     
        def get_obj(self):
            return self.obj
     
        def get_act(self):
            return self.act
     
        def incr_num(self):         # Création d'une méthode : un "Seter" ou "Mutateur" dans ce cas pour modifier une info
            self.num += 1
     
        def decr_num(self):
            self.num -= 1
     
     
    # Création de listes contenant les données à afficher
    liste_pers = ["Dompteur", "Adam", "Lucy", "Pythagore", "Français", "Mime"]
    liste_obj = ["Des anneaux pour sauter", "Une pomme", "Un gourdin", "Une équère", "Une baguette", "Des gants blancs"]
    liste_act = ["Dompter un fauve", "Manger une pomme", "Taper avec un gourdin", "Mesurer un angle", "Manger une baguette", "Mimer en silence"]
     
    # Variable permettant de choisir quelle carte sera affichée
    i = 0
     
     
    # Fonction permettant d'incrémenter le numéro de la carte à afficher
    def incr_i():
        global i
        i += 1
     
     
    # Instance de classe
    carte_i = FlashCard(i, liste_pers[i], liste_obj[i], liste_act[i])
     
    print("Cartes en mémoire : ")
     
    ##########################
    #    Partie affichage    #
    ##########################
     
    # Création d'une fenêtre TK
    root = Tk()
    # Définir la couleur de fond de la fenêtre
    root.configure(bg="white")
     
     
    # Création d'une fonction d'affichage d'une fenêtre contenant les textes de la classe
    def affiche_cart():
     
        num_carte = Label(root, text=str(carte_i.get_num()), bg="white", width=5, font=("Courier Bold", 30))      # Création d'un Label
        pers_carte = Label(root, text=str(carte_i.get_pers()), bg="#f2f8a7", width=25)
        obj_carte = Label(root, text=str(carte_i.get_obj()), bg="#b7e8e6", width=25)
        act_carte = Label(root, text=str(carte_i.get_act()), bg="#d8b7e8", width=25)
        btn_next = Button(root, text="Suivant >", command=incr_i())
     
        num_carte.pack(padx=10, pady=10)           # Placement du Label
        pers_carte.pack(padx=10, pady=10)
        obj_carte.pack(padx=10, pady=10)
        act_carte.pack(padx=10, pady=10)
        btn_next.pack(padx=10, pady=10)
     
        root.mainloop()
     
     
    print("Personnes : ", liste_pers)
    print("Actions : ", liste_act)
    print("Objets : ", liste_obj)
     
    # Appel de la fonction d'affichage de la carte correspondant à i
    affiche_cart()
    Merci beaucoup !

  2. #2
    Membre régulier
    Inscrit en
    Juillet 2013
    Messages
    80
    Détails du profil
    Informations forums :
    Inscription : Juillet 2013
    Messages : 80
    Points : 119
    Points
    119
    Par défaut
    Bonjour,

    Désolé je suis sur mobile donc difficile de debugguer ...

    A première vue j’ai limpression que vous incrémentez une variable («*i*») mais celle ci ne semble pas être utilisée dans la frame tkinter...

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Points : 30
    Points
    30
    Par défaut
    Bonjour

    Mon idée était que Tkinter affiche les valeurs de l'instance :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    carte_i = FlashCard(i, liste_pers[i], liste_obj[i], liste_act[i])
    de la classe
    Les valeurs étant prises dans le rang "i" des trois tableaux.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    liste_pers = ["Dompteur", "Adam", "Lucy", "Pythagore", "Français", "Mime"]
    liste_obj = ["Des anneaux pour sauter", "Une pomme", "Un gourdin", "Une équère", "Une baguette", "Des gants blancs"]
    liste_act = ["Dompter un fauve", "Manger une pomme", "Taper avec un gourdin", "Mesurer un angle", "Manger une baguette", "Mimer en silence"]
    De plus, la fonction s'appelant "loop", je pensais il s'agissait d'une boucle qui devrait donc tourner pour rafraîchir la fenêtre.

    Et c'est dans tout ça qu'il doit y avoir une erreur...

    P.S. Quand je change la valeur de "i" à la main et que je relance le programme, la fenêtre affiche bien les nouvelles "string" désignées par "i". Donc au moins cette partie, ça devrait aller...

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 442
    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 442
    Points : 37 034
    Points
    37 034
    Par défaut
    Salut,

    Citation Envoyé par Yobeco Voir le message
    J'ai créé une fonction qui devrait être activée par une pression sur le bouton, mais rien ne se passe...
    • Ou la variable "i" n'évolue pas comme je l'imagine (elle ne bouge pas), mais je ne sais pas encore utiliser un débogueur pour observer ça...
    • Ou c'est la fenêtre qui ne se rafraîchit pas, et donc qui ne prend pas en compte l'évolution de ma variable "i".

    Je penche plus vers la seconde hypothèse, mais on ne sait jamais...
    La commande "print" devrait vous permettre de répondre à ces questions.
    Après pour apprendre à utiliser tkinter, pas la peine de vous lancer dans des codes aussi compliqués: vous allez juste vous perdre à vous poser des questions sans trop savoir ce qui marche ou pas...

    - W

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Points : 30
    Points
    30
    Par défaut
    Merci pour vos conseils.

    La commande "print" devrait vous permettre de répondre à ces questions.
    Effectivement... Je vais essayer ça.

    Après, pour apprendre à utiliser tkinter, pas la peine de vous lancer dans des codes aussi compliqués
    Très juste... Je viens de réaliser un code beaucoup plus court pour étudier mon problème : une simple fenêtre avec un "cadre" et un "bouton".
    Le voici :

    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
     
    # Import de la bibliothèque TKinter
    from tkinter import *
     
    # Création de la fenêtre et d'un cadre
    root = Tk()
    frame = Frame(root, background="#f6d5ba")
    frame.pack()
     
    # Création d'un canevas où afficher la valeur "i" plus tard
    cnv = Canvas(frame, width=200, height=100, bg="white")
    cnv.pack(padx=20, pady=10)
     
    # Variable à incrémenter
    i = 0
    print(i)
     
    # Fonction d'incrémentation de "i"
    def incr_i():
        global i
        i += 1
        print(i)
     
    # Création d'un bouton d'incrémentation
    btn = Button(frame, text="+1", command=incr_i())
    btn.pack(pady=10)
     
    # Appel de la fonction d'affichage
    root.mainloop()
    Le résultat est très surprenant pour moi.

    Au lancement de la fenêtre, la console m'affiche 2 "print" : le "0" avant incrémentation et un "1" (D'où sort-il ???) , alors que je ne clique pas sur le bouton...

    Si je remplace "i += 1" par "i += 2" dans "def incr_i():", mon deuxième "print" devient "2".
    Quand j'enlève ", command=incr_i()" des paramètres du bouton, seul le "print" 0 apparaît.
    Il semble donc bien que le bouton se "déclenche" tout seul et incrémente "i" au démarrage.

    Par contre, quand j'appuie sur le bouton : aucun "print" n'apparaît !!!
    J'aurais créé un bouton qui se déclencherait seulement au démarrage mais pas en le cliquant ???

    Je suis perplexe... Qu'est-ce qui m'échappe donc ?

    Mais au moins, je crois que cette fois j'ai mis le doigt directement sur mon ignorance...

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 442
    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 442
    Points : 37 034
    Points
    37 034
    Par défaut
    Salut,

    Citation Envoyé par Yobeco Voir le message
    Par contre, quand j'appuie sur le bouton : aucun "print" n'apparaît !!!
    J'aurais créé un bouton qui se déclencherait seulement au démarrage mais pas en le cliquant ???
    voilà... et toute la différence est entre command=incr() et command=incr...
    Çà se ressemble mais dans un cas on passe à command le résultat de l'appel à la fonction et dans l'autre la fonction à appeler.

    Subtil? La machine se contente d'exécuter les instructions que vous lui demandez d'exécuter, ni plus ni moins...

    La difficulté est d'arriver à relire son code en se mettant à la place de la machine.

    Parfois on ne comprend pas comment le code qu'on a écrit se comporte de façon inattendue... et on a beau le relire, on passera à côté jusqu'à se qu'on se pose de bonnes questions.

    Et vous n'êtes qu'au début, car vous ne faites pas de choses très compliquées, juste jouer avec les fonctionnalités de base de tkinter. Imaginez avoir à écrire un programme un peu touffu de quelques milliers de lignes...

    - W

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Points : 30
    Points
    30
    Par défaut
    Voilà... et toute la différence est entre command=incr_i() et command=incr_i ...
    Ah ouiiii !
    Effectivement !!! Et c'est un peu traître en plus, parce qu'il n'y avait aucun message d'erreur...

    Maintenant "i" s'actualise bien dans ma petite fenêtre d'essai. :-)

    La difficulté est d'arriver à relire son code en se mettant à la place de la machine.
    Parfois on ne comprend pas comment le code qu'on a écrit se comporte de façon inattendue... et on a beau le relire, on passera à côté jusqu'à se qu'on se pose de bonnes questions.
    C'est là qu'étaient mes plus grandes craintes quand j'ai commencé à programmer : rester bloqué dans mon incompréhension... (Et c'est là que la communauté est un joker qui permet probablement à beaucoup d'apprentis de ne pas abandonner, dégoûtés... )

    Imaginez avoir à écrire un programme un peu touffu de quelques milliers de lignes...
    C'est pour ça que j'ai toujours eu de l'admiration pour les développeurs : esprit logique et structuré, esprit de synthèse, imagination, recherche de l'efficacité, ténacité face à la difficulté... :-)

    Dés que j'ai le temps, j'applique cette correction à mon projet de "Cartes flashs" et je reviens.

    Merci !

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 442
    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 442
    Points : 37 034
    Points
    37 034
    Par défaut
    Salut,

    Citation Envoyé par Yobeco Voir le message
    Effectivement !!! Et c'est un peu traître en plus, parce qu'il n'y avait aucun message d'erreur...
    Quand il y a un message d'erreur, c'est (presque) facile!
    Ici, le problème est dans la traduction de l'idée en code et le manque de relecture: c'est devant vos yeux mais vous ne le voyez pas.

    Citation Envoyé par Yobeco Voir le message
    C'est là qu'étaient mes plus grandes craintes quand j'ai commencé à programmer : rester bloqué dans mon incompréhension...
    Le code, c'est juste du texte que vous pouvez modifier sans trop de problèmes (imaginez une construction en bois ou en métal, défaire et refaire est plus compliqué). Essayez de réduire votre problème à un code minimal qui permette de reproduire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from tkinter import *
     
    i = 0
    print(i)
     
    def incr_i():
        global i
        i += 1
        print(i)
     
    btn = Button(text="+1", command=incr_i)
    btn.pack()
     
    mainloop()
    et supprimez les commentaires: vous allez avoir tendance à lire les commentaires alors que vous devez apprendre à relire le code (çà ne vous aide pas à faire cet effort!).

    - W

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Points : 30
    Points
    30
    Par défaut
    Merci pour vos conseils

    J'ai donc réalisé un nouveau code réduit au minimum pour arriver à mon but :
    "Faire afficher dans un "Label" le contenu d'une case de "liste" puis modifier la valeur affichée en modifiant l'index de la case lue."

    Après avoir écumé de nombreuses documentations dans lesquelles j'ai découvert ce qu'est une "variable de contrôle" dont StringVar(), la méthode .set() associée ainsi que l'argument textvariable de l'objet "Label"... ça y est, ça fonctionne (au moins dans mon exemple simple !)

    Voici donc mon code minimaliste :

    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
     
    # "TKinter - Pascal ORTIZ.pdf" à partir de page 54
    # https://infoforall.fr/python/python-act060.html#partie_04
     
    from tkinter import *
     
    root = Tk()
    msg = StringVar(master = root)
    frame = Frame(root, background="lavender")
    frame.pack()
     
    i=0
     
    liste = ["Case n°0", "Case n°1", "Case n°2", "Case n°3"]
    msg.set(liste[i])
     
    lbl=Label(frame, textvariable = msg)
    lbl.pack(padx=20, pady=10)
     
    def incr():
        global i
        i += 1
        if i>3:                  # Pour ne pas sortir du tableau
            i=0
    #     else:
    #         i=i
        print(" i vaut :", i)    # Surveiller l'état de "i"
        msg.set(liste[i])        # Injecter la valeur de "i" dans l'objet "msg" de type StringVar()
     
     
    bouton = Button(root, text="Suivant", command=incr)
    bouton.pack()
     
    root.mainloop()
    Donc, l'étape suivante, c'est essayer avec plusieurs tableaux et plusieurs labels, toujours dans un code réduit...
    Puis appliquer tout ça, par la suite, au code de mon projet :-)

    Je vous tiens au courant !

    Merci encore !

  10. #10
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 442
    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 442
    Points : 37 034
    Points
    37 034
    Par défaut
    La même chose en utilisant les fonctionnalités des Variables:
    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
    from tkinter import *
     
    liste = ["Case n°0", "Case n°1", "Case n°2", "Case n°3"]
     
    root = Tk()
    index = IntVar()
    label=Label()
    label.pack()
    index.trace('w', lambda *args: label.configure(text=liste[index.get()]))
    index.set(0)
    bouton = Button(text="Suivant",
                    command=lambda: index.set((index.get() + 1) % len(liste)))
    bouton.pack()
     
    mainloop()
    - W

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Points : 30
    Points
    30
    Par défaut
    C'est beaucoup plus court !

    Je vais étudier votre code... Au premier coup d’œil, il me manque pas mal de connaissances sur les "fonctionnalités des Variables"

    Merci

  12. #12
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Points : 30
    Points
    30
    Par défaut
    Bon, ben ok...
    Je suis épaté par cette belle mécanique miniaturisée, mélange de connaissances approfondies des fonctions (.trace, lambda) et d'astuces efficaces (modulo)...

    J’émets l'hypothèse que vous ne l'avez pas improvisée pour moi, mais construite à partir d'éléments sortis d'un grand sac rempli tout au long de votre expérience.

    Voici votre code avec des commentaires ajoutés pour aider la compréhension de ceux qui liront ce post plus tard :
    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
     
    from tkinter import *
     
    liste = ["Case n°0", "Case n°1", "Case n°2", "Case n°3"]
     
    root = Tk()
    index = IntVar()       # Création d'un objet de class IntVar()
    label=Label()
    label.pack()
     
    # Methode ".trace" : pour détecter quand "index" est modifié --> argument 'w': quand il subit une écriture
    # lambda est une fonction anonyme : mini-fonction d’une ligne à la volée, sans nom
    # Elle utilisera un nombre variable d'arguments --> *rags
    # Elle injecte le texte à afficher dans l'argument "text" de l'étiquette "label"
    # et ce texte, c'est le contenu de la case de la liste correspondant à l'index donnée par "index.get()"
    index.trace('w', lambda *args: label.configure(text=liste[index.get()]))
     
    # Assigner la valeur 0 à la variable de contrôle "index" pour initialiser le comptage
    index.set(0)
     
    # Création du bouton qui lance une nouvelle fonction anonyme "lambda" pour modifier la valeur de "index"
    # Cette mini-fonction assigne à "index" le reste sa propre valeur incrémentée de 1 divisée par la longueur de la liste
    # Ce qui produit un cycle progressif de valeurs de 0 à 3... (dés qu'on arrive sur un multiple, le modulo retourne à 0)
    # C'est beau ! Il fallait y penser !!!
    bouton = Button(text="Suivant", command=lambda: index.set((index.get() + 1) % len(liste)))
     
    bouton.pack()
     
    mainloop()
    Sources de documentation :
    .trace / *args : https://python-para-impacientes.blog...n-tkinter.html
    *args : https://pageperso.lis-lab.fr/~stefan...on/slides4.pdf

    Merci

    Quand j'ai le temps, je retourne au code principal de mon projet. Et je reviens pour clore le sujet. (enfin j'espère...)

  13. #13
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 442
    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 442
    Points : 37 034
    Points
    37 034
    Par défaut
    Citation Envoyé par Yobeco Voir le message
    Je suis épaté par cette belle mécanique miniaturisée, mélange de connaissances approfondies des fonctions (.trace, lambda) et d'astuces efficaces (modulo)...
    Il n'y a rien de magique. Programmer quelque part est un métier. Et comme dans tous les métiers, c'est la pratique qui vous permet de progresser après une formation initiale.

    Citation Envoyé par Yobeco Voir le message
    J’émets l'hypothèse que vous ne l'avez pas improvisée pour moi, mais construite à partir d'éléments sortis d'un grand sac rempli tout au long de votre expérience.
    C'est pour vous montrer qu'on peut faire bien autre chose avec les Variables... mais dans ce cas particulier, on peut s'en passer et écrire:
    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
    root = Tk()
     
    label=Label()
    label.pack()
     
    index = 0
    def do_update():
        global index
        label.configure(text=f'Case n°{index}')
        index = (index + 1) % 4
     
    do_update()
    bouton = Button(text="Suivant", command=do_update)
    bouton.pack()
     
    mainloop()
    et de fait, il y a des tas de solutions possibles suivant ses connaissances (dans un premier temps on fait avec ce qu'on sait) et ses besoins (plus tard, on arbitre entre plusieurs options...).

    Quand on écrit un exemple, on se force à... un certain style pour montrer quelque chose. Ce n'est pas de la programmation, c'est de la matière à penser.

    - W

  14. #14
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Points : 30
    Points
    30
    Par défaut
    Il n'y a rien de magique.
    Ça, j'en suis sûr...

    Programmer, quelque part, est un métier.
    Quand on peut s'y dédier, c'est idéal pour progresser.
    C'est ce qui nous manque à nous, les autodidactes...
    Et c'est par manque d'une formation initiale structurée qu'on pourrait être ressentis comme "un peu lourds" sur les forums.

    et de fait, il y a des tas de solutions possibles suivant ses connaissances (dans un premier temps on fait avec ce qu'on sait) et ses besoins (plus tard, on arbitre entre plusieurs options...).
    Quand on écrit un exemple, on se force à... un certain style pour montrer quelque chose.
    Ça, ça ressemble beaucoup aux arts martiaux ou à la musique
    La créativité commence à naître à partir d'un certain niveau de maîtrise.
    Ce point de vue place la programmation comme un art, comme l'architecture

    Ce n'est pas de la programmation, c'est de la matière à penser.
    Oui, je commence à comprendre.
    Moi, je vois la programmation comme une sorte de "meccano" virtuel presque vivant (dans le sens où le langage lui-même évolue au fil des versions) et dont on doit découvrir petit à petit toutes les pièces et les règles.
    Au début, j'ai une idée, un projet. Mais quand je commence, le code devient un "être" que je fais évoluer (J'ai surtout fait du "C Arduino" avant le Python). Il devient un centre d'intérêt en soi... Il devient "de la matière à penser".

    C'est pour vous montrer qu'on peut faire bien autre chose avec les Variables... mais dans ce cas particulier, on peut s'en passer et écrire:
    Ce nouveaux code est intéressant. J'ai découvert les f-string. C'est très utile !
    Cependant, cette version ne va plus chercher les valeurs dans une liste...

    Par ailleurs, concernant mon projet d'application d'apprentissage, vu que la liste risque de dépasser 136 valeurs et que l'utilisateur devra pouvoir en modifier le contenu, je pense plutôt utiliser un fichier .csv à la place des listes dans les prochaines versions de mon "être-code" en cours d'évolution.
    Donc, l'aventure ne fait que commencer !

    Yonnel

  15. #15
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Points : 30
    Points
    30
    Par défaut
    Pas beaucoup de temps en cette période pour coder, mais voici une version fonctionnelle de mon code.
    Les valeurs de chaque carte s'actualisent dans l'interface quand on appuie sur le bouton "Suivant".

    C'est une version réalisée avec mes compétences basiques.
    À noter que je me suis rendu compte que je n'avais plus besoin d'utiliser une "class", je l'ai enlevée.

    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
    80
    81
    # Création d'une fenêtre pour afficher les "flash cards" constituées de 4 informations
    # Bientôt des images comme 5ème information
    # Version du code sans utiliser de "class"
     
    # Import de la bibliothèque TKinter
    from tkinter import *
     
    ########################
    #    Partie logique    #
    ########################
     
    # Création de listes contenant les données à afficher
    # Bientôt remplacé par un .CSV
    liste_num = ["00", "01", "02", "03", "04", "05"]
    liste_pers = ["Dompteur", "Adam", "Lucy", "Pythagore", "Français", "Mime"]
    liste_obj = ["Des anneaux pour sauter", "Une pomme", "Une racine", "Une équère", "Une baguette", "Des gants blancs"]
    liste_act = ["Dompter un fauve", "Manger une pomme", "Taper avec un gourdin", "Mesurer un angle", "Manger une baguette", "Mimer en silence"]
     
    # Index de la carte à afficher
    i = 0
     
    ##########################
    #    Partie affichage    #
    ##########################
     
    # Création d'une fenêtre TK
    root = Tk()
    # Définir la couleur de fond de la fenêtre
    root.configure(bg="white")
     
    # Création des variables de contrôle
    num_i = StringVar(master=root)
    pers_i = StringVar(master=root)
    act_i = StringVar(master=root)
    obj_i = StringVar(master=root)
     
     
    # Fonction permettant d'incrémenter l'index de la carte à afficher
    def incr_i():
        global i
        i += 1
        if i > (len(liste_pers)-1):         # Pour ne pas sortir du tableau
            i = 0
        print(" i vaut:", i)                # Surveiller l'évolution de "i"
        num_i.set(liste_num[i])             # Injecter la valeur de l'élément d'indice "i" dans l'objet "num_i" de type StringVar()
        pers_i.set(liste_pers[i])
        act_i.set(liste_act[i])
        obj_i.set(liste_obj[i])
     
     
    # Création d'une fonction d'affichage d'une fenêtre contenant les textes de la classe
    def affiche_cart():
     
        num_i.set(liste_num[i])
    #    print("liste_num=", num_i)
        pers_i.set(liste_pers[i])
        act_i.set(liste_act[i])
        obj_i.set(liste_obj[i])
     
        num_carte = Label(root, textvariable=num_i, bg="white", width=5, font=("Courier Bold", 30))      # Création d'un Label
        pers_carte = Label(root, textvariable=pers_i, bg="#f2f8a7", width=25)
        obj_carte = Label(root, textvariable=obj_i, bg="#b7e8e6", width=25)
        act_carte = Label(root, textvariable=act_i, bg="#d8b7e8", width=25)
        btn_next = Button(root, text="Suivant >", command=incr_i)
     
        num_carte.pack(padx=10, pady=10)           # Placement du Label
        pers_carte.pack(padx=10, pady=10)
        obj_carte.pack(padx=10, pady=10)
        act_carte.pack(padx=10, pady=10)
        btn_next.pack(padx=10, pady=10)
     
        root.mainloop()
     
     
    # print("Cartes en mémoire : ")
    # print("Personnes : ", liste_pers)
    # print("Actions : ", liste_act)
    # print("Objets : ", liste_obj)
     
    # Appel de la fonction d'affichage de la carte correspondant à l'incide "i"
    affiche_cart()
    Je vais essayer de poster prochainement une version plus courte utilisant les mini-fonctions.

    Merci !

  16. #16
    Nouveau membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2019
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Nicaragua

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2019
    Messages : 68
    Points : 30
    Points
    30
    Par défaut
    En fait, comme mon bouton doit actualiser plusieurs champs, je ne peux donc pas utiliser les fonctions anonymes qui doivent rester très courtes...

    Cependant, j'utilise bien le modulo qui est très pratique.

    Voici le code de mon projet qui a bien avancé depuis :

    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
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
     
    # Afficher des "Flash cards" constituées d'une image et de 4 informations
    # Données venant d'un fichier CSV !
    # Avec une barre de menu (en cours...)
    # Mode édition : Champs et boutons visibles
     
    # Import de la bibliothèque "TKinter"
    from tkinter import *
    # Import de la bibliothèque "Pandas" pour les .CSV
    import pandas
     
    #########################
    #    Base de données    #
    #########################
     
    # Creation d'un objet "DataFrame" à partir d'un fichier .csv
    domsys=pandas.read_csv("DOM-SYS.csv", delimiter=",", index_col=0)
     
    # Index du CSV de la carte à afficher
    i = -1                   # Commencer par -1 pour arriver sur 0 à la première incrémentation
     
    ##########################################
    #    Création de la fenêtre principale   #
    ##########################################
     
    # Création d'une fenêtre TK
    root = Tk()
     
    # Configuration de la fenêtre
    root.configure(bg="white")
    root.title("DOM-SYS")
    root.resizable(height=True, width=True)
    root.minsize(340, 550)     # Taille minimale de la fenêtre (en cas de redimentionnement)
     
    root.iconphoto(False, PhotoImage(file='Icone/Logo-DOM-SYS-150px.png'))      # Définir une icône pour l'application. Mais invisible sous Ubuntu ?
     
    ###############################################
    #    Préparation du contenu de l'interface    #
    ###############################################
     
    logo = PhotoImage(file='img/Acc.png')                          # Préparer une variable pour afficher une image d'accueil
    ici_img = PhotoImage(file='Icone/ici-22x22.png')
    cnv_img = Canvas(root, width=300, height=300, bg='ivory')      # Canvas où sera placée l'image
    frame_bt = Frame(root, background="white")                     # Cadre pour réunir les boutons
     
     
    # Création des variables de contrôle
    nom_i = StringVar(master=root)
    pers_i = StringVar(master=root)
    act_i = StringVar(master=root)
    obj_i = StringVar(master=root)
    demande = StringVar(master=root)
     
    # Fonction pour afficher les informations après la modification de "i"
    def update():
        global i                                       # Aller chercher les variables globales
        global logo
        print(" i vaut:", i)                           # Surveiller l'évolution de "i"
        logo = PhotoImage(file=domsys.loc[i, "Img"])           # Charger l'adresse de l'image qui correspond à la cellule d'indice "i"
        cnv_img.delete('all')                          # Effacer l'ancienne image
        cnv_img.create_image(150, 150, image=logo)     # Afficher l'image correspondant à la nouvelle adresse (indice "i")
        nom_i.set(domsys.loc[i, "Valeur"])             # Injecter la valeur du DataFrame d'index de ligne "i" dans l'objet "num_i" de type StringVar()
        pers_i.set(domsys.loc[i, "Pers"])
        act_i.set(domsys.loc[i, "Act"])
        obj_i.set(domsys.loc[i, "Obj"])
     
    # Fonction permettant d'incrémenter l'index de la carte à afficher
    # "domsys.shape" est une méthode qui renvoit un tuple contenant la taille du DataFrame (ligne,colonne)
    # "domsys.shape[0]" renvoie donc un "int" correspondant au nombre de lignes
    def incr_i():
        global i
        i = ((i + 1) % domsys.shape[0])     # Pour ne pas sortir du tableau
        update()
     
    # Fonction permettant de décrémenter l'index de la carte à afficher
    def decr_i():
        global i
        i = ((i - 1) % domsys.shape[0])     # Pour ne pas sortir du tableau
        update()
     
    # Fonction permettant d'arriver directement à l'index de la carte à afficher
    def ici():
        global i
        global logo
    # https://askcodez.com/comment-obtenir-le-numero-de-ligne-dans-le-dataframe-dans-les-pandas.html
    # https://moonbooks.org/Articles/Comment-compter-le-nombre-doccurrence-des-elements-dans-la-colonne-dune-dataframe-avec-pandas-en-python-/
    # Si il n'y a aucune occurence de la valeur retournée par "demande.get()" dans la colonne 'Valeur' (taille de la liste = 0) Alors, retourner à l'index 0
        if (len(domsys[domsys['Valeur'] == demande.get()]))==0:
            i = 0
            logo = PhotoImage(file="img/VI.png")          # Charger l'adresse de l'image d'erreur
            cnv_img.delete('all')                         # Effacer l'ancienne image
            cnv_img.create_image(150, 150, image=logo)    # Afficher l'image d'erreur
            nom_i.set('***')                              # N'afficher aucune valeur
            pers_i.set('***')
            act_i.set('***')
            obj_i.set('***')
    # Si la valeur existe dans la liste, mettre dans "i" la valeur de l'index de la ligne où se trouve cette valeur
        else:
            i = domsys.loc[domsys['Valeur'] == demande.get()].index[0]
            update()
     
    # Fonction d'écriture des données dans le .CSV
    def enreg():
        domsys.loc[i, "Pers"] = pers_i.get()     # Modification du "DataFrame" en fonction des données présentes dans les entrées
        domsys.loc[i, "Act"] = act_i.get()
        domsys.loc[i, "Obj"] = obj_i.get()
        domsys.to_csv('DOM-SYS.csv')             # Écriture du "DataFrame" modifié dans le .CSV (écrasement)
     
    #############################################
    #    Création de la fonction d'affichage    #
    #############################################
     
    # Création de la fenêtre contenant les informations
    def affiche_cart():
     
        nom_i.set('.')            # Ne pas afficher de valeur au démarrage
        pers_i.set('Personne')
        act_i.set('Action')
        obj_i.set('Objet')
     
    # Création des Widgets
        add_img = Button(root, text="Charger image", command=None)
        nom_carte = Label(root, textvariable=nom_i, bg="white", width=5, font=("Courier Bold", 30))      # Création d'un Label
        pers_carte = Label(root, textvariable=pers_i, bg="#f2f8a7", width=25)
        pers_entr=Entry(root, textvariable=pers_i, width=25)
        act_carte = Label(root, textvariable=act_i, bg="#d8b7e8", width=25)
        act_entr=Entry(root, textvariable=act_i, width=25)
        obj_carte = Label(root, textvariable=obj_i, bg="#b7e8e6", width=25)
        obj_entr=Entry(root, textvariable=obj_i, width=25)
        btn_next = Button(frame_bt, text="Suivant >", command=incr_i)
        entree=Entry(frame_bt, textvariable=demande, width=3)
        btn_ici = Button(frame_bt, image=ici_img, command=ici)
        btn_back = Button(frame_bt, text="< Précédent", command=decr_i)
        btn_enreg = Button(root, text="Enregistrer les modifications", command=enreg)
     
        ######################################
        #    Création de la barre de menu    #
        ######################################
     
        bar_menu = Menu(root, background='#ffffff', foreground='#000000',
                       activebackground='#f7f1d0', activeforeground='#000000')
        root.config(menu=bar_menu)
     
        # Fonctions activées par les menus
        def mode_feuil():               # Cacher les champs d'entrées
            add_img.pack_forget()
            pers_entr.pack_forget()
            act_entr.pack_forget()
            obj_entr.pack_forget()
            btn_enreg.pack_forget()
     
        def vider():                    # Cacher tous les widgets (Pour un réaffichage)
            cnv_img.pack_forget()
            add_img.pack_forget()
            nom_carte.pack_forget()
            pers_carte.pack_forget()
            pers_entr.pack_forget()
            act_carte.pack_forget()
            act_entr.pack_forget()
            obj_carte.pack_forget()
            obj_entr.pack_forget()
            frame_bt.pack_forget()
            btn_back.pack_forget()
            entree.pack_forget()
            btn_ici.pack_forget()
            btn_next.pack_forget()
            btn_enreg.pack_forget()
     
        def mode_edit():               # Afficher tous les widgets (entrées incluses)
            vider()
            cnv_img.pack(padx=15, pady=15)
            cnv_img.create_image(150, 150, image=logo)
            add_img.pack()
            nom_carte.pack(padx=10, pady=5)
            pers_carte.pack(padx=10, pady=5)
            pers_entr.pack()
            act_carte.pack(padx=10, pady=5)
            act_entr.pack()
            obj_carte.pack(padx=10, pady=5)
            obj_entr.pack()
            frame_bt.pack()
            btn_back.pack(side=LEFT, padx=10, pady=15)
            entree.delete(0,'end')                     # Vider le champ pour éviter les accumulations
            entree.insert(0, "00")                     # Mettre 0 comme valeur par défaut dans "entree"
            entree.pack(side=LEFT, padx=5, pady=15)
            btn_ici.pack(side=LEFT, padx=5, pady=10)
            btn_next.pack(side=RIGHT, padx=10, pady=10)
            btn_enreg.pack(padx=10, pady=10)
     
        def quit():                                    # Ferme le programme
            sys.exit()
     
        # Menu "Fichier"
        fichier = Menu(bar_menu, tearoff=0, background='#ffffff', foreground='#000000',
                       activebackground='#f7f1d0', activeforeground='#000000')
        fichier.add_command(label="Ouvrir", command=None)
        fichier.add_command(label="Enregistrer", command=None)
        fichier.add_command(label="Créer une sauvegarde", command=None)
        fichier.add_separator()
        fichier.add_command(label="Fermer", command=quit)
        bar_menu.add_cascade(label="Fichier", menu=fichier)
     
        # Menu "Edition"
        edition = Menu(bar_menu, tearoff=0, background='#ffffff', foreground='#000000',
                       activebackground='#f7f1d0', activeforeground='#000000')
        edition.add_command(label="Mode feuilletage", command=mode_feuil)
        edition.add_command(label="Mode édition", command=mode_edit)
        bar_menu.add_cascade(label="Édition", menu=edition)
     
        # Menu "Affichage"
        affich = Menu(bar_menu, tearoff=0, background='#ffffff', foreground='#000000',
                       activebackground='#f7f1d0', activeforeground='#000000')
        affich.add_command(label="Mode clair", command=None)
        affich.add_command(label="Mode sombre", command=None)
        # affich.add_command(label="Vider", command=vider)
        bar_menu.add_cascade(label="Affichage", menu=affich)
     
        # Menu "Aide"
        aide = Menu(bar_menu, tearoff=0, background='#ffffff', foreground='#000000',
                       activebackground='#f7f1d0', activeforeground='#000000')
        aide.add_command(label="Manuel", command=None)
        aide.add_command(label="À propos de DOM-SYS", command=None)
        bar_menu.add_cascade(label="Aide", menu=aide)
     
        mode_edit()
        mode_feuil()
     
        root.mainloop()
     
    # Appel de la fonction d'affichage 
    affiche_cart()
    En tous cas, le problème est résolu.

    Merci, merci !

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

Discussions similaires

  1. [Python 2.X] Interface Tkinter pour questionnaire
    Par Invité dans le forum Tkinter
    Réponses: 1
    Dernier message: 27/04/2017, 17h03
  2. Entry interface Tkinter
    Par Cerise22 dans le forum Tkinter
    Réponses: 2
    Dernier message: 05/07/2016, 15h35
  3. importer une liste à partir d'une interface Tkinter
    Par paxapaxa dans le forum Général Python
    Réponses: 7
    Dernier message: 09/06/2016, 22h06
  4. pb interface tkinter dans fichier à part
    Par v_floyd_6 dans le forum Tkinter
    Réponses: 2
    Dernier message: 24/04/2008, 17h33
  5. [matplotlib] Croubes dans une interface tkinter
    Par vinzzzz dans le forum Tkinter
    Réponses: 2
    Dernier message: 08/12/2006, 15h34

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