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 :

Comment visualiser qu'un label à le focus


Sujet :

Tkinter Python

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

    Citation Envoyé par Cemalatowilo Voir le message
    Je suis désolé wiztricks, mais je bloque déjà sur la méthode trace d'une variable tkinter.
    Je ne trouve aucune doc à ce sujet digne de ce nom.
    Il ne faut pas vous bloquer la dessus.
    L'important, c'est le mécanisme qui associe modification d'une valeur à la notification des entités intéressées.
    C'est lui qui permet de "cloisonner" les différentes entités et de partitionner le tout "global" de départ.

    On aurait pu écrire çà juste avec des fonctions Python: çà fonctionnerait pareil, juste qu'on aurait écrit du code pour rien.

    Tenez, j'ai utilisé trace et fabriqué ma liste de callbacks ignorant que je pouvais faire sans (i.e. on peut ajouter autant de callbacks qu'on veut).

    Quand vous regardez la richesse les bibliothèques standards de Python (ou de celles de tkinter) impossible de tout savoir. Et quand on code, on arbitre entre chercher dans la documentation (qu'on n'a peut être pas sous la main ou la flemme d'ouvrir) et coder par soi-même (en ré-inventant parfois la roue).

    Plus tard, la tête reposée, on peut se donner un temps pour lire/relire la documentation et y découvrir que pour tel code, on aurait pu utiliser telle ou telle fonctionnalité (si on avait "su").

    Pire, une bibliothèque, c'est du savoir faire en boîte. Inutile de la lire si vous ne vous posez pas de bonnes questions sur les problèmes qu'elle va permettre de vous résoudre. C'est un peu comme les vieux outils qu'on voit dans les brocantes, pas facile de savoir à quoi ils pouvaient servir sans la culture technique de l'époque.

    Citation Envoyé par Cemalatowilo Voir le message
    Elle semble posséder 3 paramètres, quels sont-ils? A quoi correspond 'w' qui revient systématiquement comme premier paramètre
    Çà c'est un problème général "python".
    Python est un langage interprété dans lequel il serait inefficace de vouloir tout coder.
    Donc on l'interface avec des bibliothèques externes écrites et documentées pour d'autres langages (TCL/Tk pour tkinter, C++ pour Qt,...).

    Le minimum est de permettre au programmeur Python de savoir comment s'y retrouver entre ce qu'on utilise côté Python et la documentation officielle (c'est ce que fait la documentation tkinter).
    Après vous avez des tutos. qui couvrent en partie le sujet.

    Pour ce qui est de documentation correctes à jour et en français....

    Pour répondre à votre question, TCL documente "trace variable" comme "trace add variable" qui détaille tout çà en plusieurs paragraphes.
    Ils ne sont lisibles qu'en diagonale car çà s'applique à n'importe quelle variable TCL (et côté tkinter on n'en utilise pas beaucoup).

    De toutes façons, il faudra passer du temps à écrire des bouts de code pour vérifier qu'on a bien compris ce que çà dit. Donc on fait "à l'économie" en regardant si on peut résoudre le problème qu'on se pose "avec" et en zappant une grande partie du reste (souvent à tord).

    - W

  2. #22
    Membre du Club
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Points : 52
    Points
    52
    Par défaut
    Citation Envoyé par Beginner. Voir le message
    Salut,
    Voici les premiers liens qui me sont venus : https://effbot.org/tkinterbook/variable.htm et https://kite.com/python/docs/Tkinter.StringVar.trace...

    On a :



    Ben moi je n'en vois que deux : mode et callback.

    Le "w" c'est pour "write" (quand "la variable est écrite" ---> quand elle est modifiée alors exécute la fonction callback).
    Merci pour votre réponse.
    Mais je n'avais pas penser à regarder dans l'aide de tkinter avec la fonction Help().
    Et, si j'ai bien compris il vaut mieux utiliser la fonction trace_add().

  3. #23
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 302
    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 302
    Points : 36 801
    Points
    36 801
    Par défaut
    Salut,

    Citation Envoyé par Cemalatowilo Voir le message
    Et, si j'ai bien compris il vaut mieux utiliser la fonction trace_add().
    Ce sont les mêmes.

    Côté tkinter, trace, trace_variable sont identiques et exécutent la commande TCL "trace variable" qui équivaut côté TCL à "trace add variable".
    Côté tkinter, trace_add va exécuter le TCL "trace add variable".

    Les cafouillages sont dus aux principes qui sont posés côté passerelle entre tkinter et Tk.

    Si trace add variable et trace variable existent côté TCL, il faut que le programmeur Python les retrouve côté tkinter.
    Et si côté tkinter, on a "trace" comme synonyme de "trace_variable", c'est peut être parce que côté TCL, trace est une commande qui s'applique à différents objets alors que côté tkinter on se retrouve avec une méthode (on sait à quel objet on l'applique).

    - W

  4. #24
    Membre du Club
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Points : 52
    Points
    52
    Par défaut
    Bonjour,
    Je pense avoir compris toutes les notions que vous m'avez gentiment fournis.
    J'ai donc repris ma maquette en la programmant en POO, pour des motifs pédagogiques (merci confinement).
    Voici donc mon nouveau code. Merci de me dire ce que vous en penser.
    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
    import tkinter as tk
    class LabelListe(tk.LabelFrame):
        def __init__(self,maitre,nombre,selection,**arg):
            arg['text']='Contient une Listebox'
            arg['bg']='Gray90'
            arg['fg']='Black'
            arg['takefocus']=1
            # Création du LabelFrame contenat le widget Listbox
            super(LabelListe,self).__init__(maitre,arg)
            self.nombre=nombre
            self.selectionne=selectionne
            self.grid()
            # Création de la Listebox
            self.lb=tk.Listbox(self,height=5,width=10,
                               highlightcolor="blue",highlightthickness=2)
            self.lb.grid(row=0,column=0,sticky="ns")
            self.lb.insert(tk.END,*range(0,30))
     
            # Le focus est donné à la Listbox quand le curseur
            # entre dans le LabelFrame et il lui est enlevé quand
            # on sort du LabelFrame en le donnant à maitre
            self.bind('<Enter>',lambda evt:self.lb.focus_set())
            self.bind('<Leave>',lambda evt:maitre.focus_set())
            # Création du widget Scrollbarr associé à la Listebox
            self.sb=tk.Scrollbar(self)
            self.sb.grid(row=0,column=1,sticky="ns")
            # Mise en relation de la Listebox et du Scrollbar
            self.lb["yscrollcommand"]=self.sb.set
            self.sb["command"]=self.lb.yview
     
            self.lb.bind('<<ListboxSelect>>',lambda evt: self.selectionListe(evt))
     
        def selectionListe(self,evt):
            if (cs:=self.lb.curselection()):
                val=int(cs[0])
                if val!=self.selectionne.get():
                    self.nombre.set(val)
     
        def MaJ(self,*arg): # l'argument *arg est obligatoire pour l'utilisation de trace_add
            if (val := self.nombre.get()) != self.selectionne.get():
                self.lb.selection_clear(0, tk.END)
                self.lb.selection_set(val)
                self.lb.see(val)
                self.lb.activate(val)
     
    class LabelAfficheur(tk.LabelFrame):
        def __init__(self,maitre,nombre,selection,**arg):
            arg['text']='Selectionné'
            arg['bg']='Misty rose'
            arg['fg']='Black'
            # Création du LabelFrame contenant le widget Label
            super(LabelAfficheur,self).__init__(maitre,arg)
            self.nombre=nombre
            self.selectionne=selectionne
            self.grid()
            # Création du Label qui affiche le nombre selectionné
            labelSelection=tk.Label(self,width=10,
                                    textvariable=self.nombre,height=6,justify="center")
            labelSelection.grid(row=0,column=0)
     
    class LabelGrille(tk.LabelFrame):
        def __init__(self,maitre,nombre,selection,**arg):
            arg['text']='Ne contient que des Labels'
            arg['bg']='Gray50'
            arg['fg']='Black'
            arg['takefocus']=1
            arg['highlightthickness']=1
            arg['highlightcolor']="red"
            # Création du LabelFrame contenant la grille de labels
            super(LabelGrille,self).__init__(maitre,arg)
            self.nombre=nombre
            self.selectionne=selectionne
            # Le focus est donné au LabelFrame quand le curseur
            # entre dans le LabelFrame et il lui est enlevé quand
            # on sort du LabelFrame en le donnant à maitre        
            self.bind('<Enter>',lambda evt:self.focus_set())
            self.bind('<Leave>',lambda evt:maitre.focus_set())
     
     
            # Création de la grille de Labels
            ligne=0
            colonne=0
            self.lab=list()
            i=0
            for j in range(0,30):
                self.lab.append(tk.Label(self,text=str(j),takefocus=0,
                                    bg="Gray90",width=3,height=1,bd=5))
                self.lab[j].bind('<Button>',lambda evt: self.Bouge(evt))
                self.lab[j].grid(row=ligne,column=colonne)
                j+=1
                ligne+=1
                if ligne>4:
                    ligne=0
                    colonne+=1
     
            self.event_add('<<Fleches>>','<Up>', '<Down>', '<Right>', '<Left>')
            self.bind('<<Fleches>>',lambda evt: self.Bouge(evt))
     
            self.mvt={'Up':-1,
                      'Down':+1,
                      'Right':+5,
                      'Left':-5}        
     
            self.grid
     
        # Fonction qui gère les flèches
        def Bouge(self,evt):
            val=self.mvt.get(evt.keysym)
            if val is None:
                val=self.lab.index(evt.widget)
            else:
                val=(nombre.get()+val)%30
            nombre.set(val)
     
        # Fonction de mise à jour de la grille. Permet de
        # visualiser le nombre choisi
        def MaJ(self,*arg): # l'argument *arg est obligatoire pour l'utilisation de trace_add
            if self.selectionne.get() is not None:
                self.lab[self.selectionne.get()]['relief']='flat'
            self.selectionne.set(nombre.get())
            self.lab[self.selectionne.get()]['relief']='groove'
     
    if __name__=="__main__":
        fp=tk.Tk()
        nombre=tk.IntVar(value=1)
        selectionne=tk.IntVar(value=1)
     
        l=list()
        for j, f in enumerate((LabelListe, LabelAfficheur,LabelGrille)):
            w= f(fp, nombre,selectionne)
            w.grid(row=0,column=j, sticky="ns")
            l.append(w)
        nombre.trace_add('write',l[2].MaJ) # L'ordre d'enregistrement de la fonction
        nombre.trace_add('write',l[0].MaJ) # dans trace est important
     
        nombre.set(0)
     
        tk.mainloop()
    Je n'en suis pas totalement satisfait pour les raisons suivantes:

    1)Je n'ai pu mettre en mémoire le précédent choix qu'en utilisant une variable IntVar() et non pas une variable interne aux classes.
    J'utilise donc 2 variables IntVar().
    Y-a-t-il un autre moyen plus pythonique et/ou plus conforme aux règles de l'art de la POO?

    2) j'ai mis les trace_add après if __name__=='__main__:
    Y-a-t-il un moyen de les mettre dans le corps des classe?
    Ne serait-ce pas plus pythonique et/ou plus conforme aux règles de l'art de la POO?

    3)Question subsidière:
    Y-a-t-il un autre moyen que celui que j'utilise pour enlever le focus à un widget (c'est à dire en le donnant à un autre)?

  5. #25
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 886
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 886
    Points : 3 725
    Points
    3 725
    Par défaut
    Salut,

    Citation Envoyé par Cemalatowilo Voir le message
    3)Question subsidière:
    Y-a-t-il un autre moyen que celui que j'utilise pour enlever le focus à un widget (c'est à dire en le donnant à un autre)?
    Je me souviens t'avoir suggéré ce moyen dans un autre fil... Perso je n'ai toujours pas trouvé un autre moyen que celui-là...
    Citation Envoyé par Cemalatowilo Voir le message
    1)Je n'ai pu mettre en mémoire le précédent choix qu'en utilisant une variable IntVar() et non pas une variable interne aux classes.
    Si tu utilises des variables "classiques" tu ne pourras pas les tracer il me semble...

    Citation Envoyé par Cemalatowilo Voir le message
    2) j'ai mis les trace_add après if __name__=='__main__:
    Y-a-t-il un moyen de les mettre dans le corps des classe?
    Ne serait-ce pas plus pythonique et/ou plus conforme aux règles de l'art de la POO?
    Tu pourrais les mettre dans une classe principale (MainClass)... Et on peut en profiter pour mettre les variables IntVar() et le bout de code qui va avec, ça fera des variables globales en moins...

    Exemple en reprenant ton code :
    Code python : 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
    import tkinter as tk
     
     
    class LabelListe(tk.LabelFrame):
        def __init__(self, maitre, nombre, selectionne, **arg):
            arg['text'] = 'Contient une Listebox'
            arg['bg'] = 'Gray90'
            arg['fg'] = 'Black'
            arg['takefocus'] = 1
            # Création du LabelFrame contenat le widget Listbox
            super(LabelListe, self).__init__(maitre, arg)
            self.nombre = nombre
            self.selectionne = selectionne
            self.grid()
            # Création de la Listebox
            self.lb = tk.Listbox(self, height=5, width=10,
                                 highlightcolor="blue", highlightthickness=2)
            self.lb.grid(row=0, column=0, sticky="ns")
            self.lb.insert(tk.END, *range(0, 30))
     
            # Le focus est donné à la Listbox quand le curseur
            # entre dans le LabelFrame et il lui est enlevé quand
            # on sort du LabelFrame en le donnant à maitre
            self.bind('<Enter>', lambda evt: self.lb.focus_set())
            self.bind('<Leave>', lambda evt: maitre.focus_set())
            # Création du widget Scrollbarr associé à la Listebox
            self.sb = tk.Scrollbar(self)
            self.sb.grid(row=0, column=1, sticky="ns")
            # Mise en relation de la Listebox et du Scrollbar
            self.lb["yscrollcommand"] = self.sb.set
            self.sb["command"] = self.lb.yview
     
            self.lb.bind('<<ListboxSelect>>', lambda evt: self.selectionListe(evt))
     
        def selectionListe(self, evt):
            cs = self.lb.curselection()
            if (cs):
                val = int(cs[0])
                if val != self.selectionne.get():
                    self.nombre.set(val)
     
        def MaJ(self, *arg):  # l'argument *arg est obligatoire pour l'utilisation de trace_add
            val = self.nombre.get()
            if val != self.selectionne.get():
                self.lb.selection_clear(0, tk.END)
                self.lb.selection_set(val)
                self.lb.see(val)
                self.lb.activate(val)
     
     
    class LabelAfficheur(tk.LabelFrame):
        def __init__(self, maitre, nombre, selectionne, **arg):
            arg['text'] = 'Selectionné'
            arg['bg'] = 'Misty rose'
            arg['fg'] = 'Black'
            # Création du LabelFrame contenant le widget Label
            super(LabelAfficheur, self).__init__(maitre, arg)
            self.nombre = nombre
            self.selectionne = selectionne
            self.grid()
            # Création du Label qui affiche le nombre selectionné
            labelSelection = tk.Label(self, width=10,
                                      textvariable=self.nombre, height=6, justify="center")
            labelSelection.grid(row=0, column=0)
     
     
    class LabelGrille(tk.LabelFrame):
        def __init__(self, maitre, nombre, selectionne, **arg):
            arg['text'] = 'Ne contient que des Labels'
            arg['bg'] = 'Gray50'
            arg['fg'] = 'Black'
            arg['takefocus'] = 1
            arg['highlightthickness'] = 1
            arg['highlightcolor'] = "red"
            # Création du LabelFrame contenant la grille de labels
            super(LabelGrille, self).__init__(maitre, arg)
            self.nombre = nombre
            self.selectionne = selectionne
            # Le focus est donné au LabelFrame quand le curseur
            # entre dans le LabelFrame et il lui est enlevé quand
            # on sort du LabelFrame en le donnant à maitre
            self.bind('<Enter>', lambda evt: self.focus_set())
            self.bind('<Leave>', lambda evt: maitre.focus_set())
     
            # Création de la grille de Labels
            ligne = 0
            colonne = 0
            self.lab = list()
            i = 0
            for j in range(0, 30):
                self.lab.append(tk.Label(self, text=str(j), takefocus=0,
                                         bg="Gray90", width=3, height=1, bd=5))
                self.lab[j].bind('<Button>', lambda evt: self.Bouge(evt))
                self.lab[j].grid(row=ligne, column=colonne)
                j += 1
                ligne += 1
                if ligne > 4:
                    ligne = 0
                    colonne += 1
     
            self.event_add('<<Fleches>>', '<Up>', '<Down>', '<Right>', '<Left>')
            self.bind('<<Fleches>>', lambda evt: self.Bouge(evt))
     
            self.mvt = {'Up': -1,
                        'Down': +1,
                        'Right': +5,
                        'Left': -5}
     
            self.grid
     
        # Fonction qui gère les flèches
        def Bouge(self, evt):
            val = self.mvt.get(evt.keysym)
            if val is None:
                val = self.lab.index(evt.widget)
            else:
                val = (self.nombre.get()+val) % 30
            self.nombre.set(val)
     
        # Fonction de mise à jour de la grille. Permet de
        # visualiser le nombre choisi
        def MaJ(self, *arg):  # l'argument *arg est obligatoire pour l'utilisation de trace_add
            if self.selectionne.get() is not None:
                self.lab[self.selectionne.get()]['relief'] = 'flat'
            self.selectionne.set(self.nombre.get())
            self.lab[self.selectionne.get()]['relief'] = 'groove'
     
     
    class MainClass():
        def __init__(self):        
            nombre = tk.IntVar(value=1)
            selectionne = tk.IntVar(value=1)
     
            l = list()
            for j, f in enumerate((LabelListe, LabelAfficheur, LabelGrille)):
                w = f(fp, nombre, selectionne)
                w.grid(row=0, column=j, sticky="ns")
                l.append(w)
            # L'ordre d'enregistrement de la fonction
            nombre.trace_add('write', l[2].MaJ)
            nombre.trace_add('write', l[0].MaJ)  # dans trace est important
            nombre.set(0)
     
     
     
    if __name__ == "__main__":
        fp = tk.Tk() # on peut mettre cette ligne dans MainClass...
        MainClass()
        tk.mainloop()

    Ceci dit j'ai changé quelques points :
    1- Dans les constructeurs des trois classes tu as mis en paramètre "selection" au lieu de "selectionne"...
    2- Il manque quelque self. : self.nombre à la place de nombre.

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

    D'abord les questions:
    Citation Envoyé par Cemalatowilo Voir le message
    1)Je n'ai pu mettre en mémoire le précédent choix qu'en utilisant une variable IntVar() et non pas une variable interne aux classes.
    Si lorsqu'on exécute number.set(value), tous les widgets se mettent à jour pour rendre compte de "value" à quoi sert de connaître la valeur "actuelle" ?
    Essentiellement à optimiser: si on est déjà à jour, il n'y a rien à faire.

    De plus chaque widget devra faire un boulot différent: rien côté Label, un peu côté Listbox et grid. Dans la mouture de code ci après, j'ai gardé la variable "interne" en guise d'exemple.

    Citation Envoyé par Cemalatowilo Voir le message
    2) j'ai mis les trace_add après if __name__=='__main__:
    Y-a-t-il un moyen de les mettre dans le corps des classe?
    "trace" et "trace_variable" sont des méthodes de number (l'IntVar qui sert de "Model"). "number" est passé en paramètre lors de la création des différents widgets, pas de soucis pour qu'ils appellent eux mêmes number.trace(...)

    Citation Envoyé par Cemalatowilo Voir le message
    Y-a-t-il un autre moyen que celui que j'utilise pour enlever le focus à un widget (c'est à dire en le donnant à un autre)?
    Lorsque l'application est "active", le "focus" désigne le widget vers lequel seront dirigées les entrées clavier. Difficile de ne pas le retirer de l'un sans le donner à un autre. Mais je n'ai peut être pas compris la question.

    Côté code, bel effort!
    Je ne peux que vous livrer ma mouture pour vous montrer comment j'adresse les soucis que vous avez exposé. Je me suis appliqué à garder l'organisation de la mouture précédente.
    Normalement vous devriez avoir des questions.

    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
    import tkinter as tk
    from tkinter.constants import *
     
    NUMBERS = list(range(30))
    LINES = 5
     
    class LabelFrame(tk.LabelFrame):
        def __init__(self, master, **kwds):
            kwds['takefocus'] = 1
            super().__init__(master, kwds)
            self.bind("<Enter>", lambda e: self.focus_set())
     
    class MyListbox(LabelFrame):
        def __init__(self, master, number):
            super().__init__(master,text="Contient une liste",bg="gray90",fg='black',
                             highlightcolor="blue",highlightthickness=2)
     
            listbox = self.listbox = tk.Listbox(self, height=5, width=10)
            listbox.insert(END, *NUMBERS)
            listbox.grid(row=0,column=0,sticky="ns")
            #   Création de l'ascenseur
            sb = tk.Scrollbar(self)
            sb.grid(row=0,column=1,sticky="ns")
            #   Mise en relation de la liste et de l'ascenseur
            listbox["yscrollcommand"] = sb.set
            sb["command"]=listbox.yview
     
            self.selected = None
            self.number = number
     
            listbox.bind('<<ListboxSelect>>', self.on_selection_change)
            number.trace_variable('w', self.on_update)
     
        def on_selection_change(self, *e):
            listbox = self.listbox
            if (cs := listbox.curselection()):
                value = int(cs[0])
                if value != self.selected:
                    self.selected = value
                self.number.set(value)
     
     
        def on_update(self, *e):
            listbox = self.listbox
            if (value := self.number.get()) != self.selected:
                listbox.selection_clear(0, END)
                listbox.selection_set(value)
                listbox.see(value)
                self.selected = value
     
     
    class MyLabel(tk.LabelFrame):
        def __init__(self, master, number):
            super().__init__(master, text="Selection",bg="Misty rose")
            label = tk.Label(self, width=10, textvariable = number, height=6, justify="center")
            label.grid(row=0,column=0) 
     
     
     
    class MyGrid(LabelFrame):
     
     
        def __init__(self, master, number):
            super().__init__(master,text="Contient des labels",bg="Gray50",
                              highlightthickness=1,highlightcolor ="red")
            self.event_add('<<arrows>>',  '<Up>', '<Down>', '<Right>', '<Left>')    
            self.bind('<<arrows>>', self.do_action)
     
            # Création de tous les labels contenant un nombre
            assert len(NUMBERS) % LINES == 0
            labels = self.labels = []  
            for c in range(0, len(NUMBERS), LINES):
                for r in range(LINES):
                    label = tk.Label(self, text=str(c + r), bg="Gray90", width=3, height=1, bd=5)
                    label.bind('<Button-1>', self.do_action)
                    label.grid(row=r, column=c)
                    labels.append(label)
     
            self.selected = None
            number.trace_variable('w', self.on_update)
            self.number = number
     
     
        motions = {
            'Up' : -1,
            'Down' : 1,
            'Left' : -LINES,
            'Right' : LINES,
            }
     
        def do_action(self, event):
            value = self.motions.get(event.keysym)
            if value is None:
                value = self.labels.index(event.widget)
            else:
                value = (self.number.get() + value) % len(NUMBERS)
            self.number.set(value)     
     
     
        def on_update(self, *e):
     
            if self.selected is not None:
                self.labels[self.selected]['relief'] = FLAT
            self.selected = self.number.get()
            self.labels[self.selected]['relief'] = GROOVE
     
     
    if __name__ == '__main__':
        root = tk.Tk()
     
        number = tk.IntVar(value=1)
     
        for j, f in enumerate((MyListbox, MyLabel, MyGrid)):
            w = f(root, number)
            w.grid(row=0,column=j, sticky="ns")
     
        number.set(0)
     
        tk.mainloop()
    - W

  7. #27
    Membre du Club
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Points : 52
    Points
    52
    Par défaut
    Bonjour et merci wiztricks,
    Je vais étudier votre réponse en détail.
    Quand au focus, je veux seulement éviter des modifications de sélection involontaires lorsque le pointeur de la souris est hors des zones de la Listbox
    ou de la grille.
    Pour se faire je veux seulement supprimer le focus sur les zones concernées, sans pour autant le donner à un autre widget, mais c'est vraiment chercher le détail.

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

    Citation Envoyé par Cemalatowilo Voir le message
    je veux seulement éviter des modifications de sélection involontaires lorsque le pointeur de la souris est hors des zones de la Listbox
    ou de la grille.
    Hmmm. En fait, c'est le "self.bind("<Enter>", lambda e: self.focus_set())" qui fait que çà marche comme çà. Il faudrait définir une autre logique (le comportement attendu) et essayer de le coder (sans se prendre les pieds avec la gestion "normale" du focus).

    - W

  9. #29
    Membre du Club
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Points : 52
    Points
    52
    Par défaut
    Bonjour,
    Ca y est j'ai modifier mon programme conformément à tes remarques.
    Je n'avais pas remarqué que la variable "selected" n'a pas a être une variable globale.
    C'est seulement un paramètre interne de la listebox et de la grille.

    J'ai encore 2 questions:
    1) Où puis-je trouver la liste des étiquettes type '<<ListboxSelect>>' et leur définition? Je n'ai rien trouvé sur la toile. A vrai dire je ne sais pas formuler ma recherche.
    Je pense qu'il doit exister le même type d'étiquette pour tous les widgets.

    2) Si j'ai bien compris toute variable écrite en majuscule dans tkinter (comme NUMBERS) est automatiquement une variable globale. Il n'est pas nécessaire de la passer en paramètres dans les déclaration de classe. très partique.
    Est-ce la même chose dans python?

  10. #30
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 886
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 886
    Points : 3 725
    Points
    3 725
    Par défaut
    Citation Envoyé par Cemalatowilo Voir le message
    2) Si j'ai bien compris toute variable écrite en majuscule dans tkinter (comme NUMBERS) est automatiquement une variable globale. Il n'est pas nécessaire de la passer en paramètres dans les déclaration de classe. très partique.
    Est-ce la même chose dans python?
    Je ne crois pas que cela soit dû au fait que le nom de la variable soit en majuscule... C'est une variable globale car elle est définie en dehors de toute fonction (et de toute classe)...

    Ce serait mieux d'éviter d'avoir une variable globale (on pourrait la passer en paramètre et en faire une "variable de classe")...

  11. #31
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 302
    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 302
    Points : 36 801
    Points
    36 801
    Par défaut
    Salut,

    Citation Envoyé par Cemalatowilo Voir le message
    1) Où puis-je trouver la liste des étiquettes type '<<ListboxSelect>>' et leur définition? Je n'ai rien trouvé sur la toile. A vrai dire je ne sais pas formuler ma recherche.
    Je pense qu'il doit exister le même type d'étiquette pour tous les widgets.
    Çà se trouve dans la documentation Tk officielle (hélas en anglais. J'avais vu passer une traduction mais je suis infoutu de la retrouver).
    On cherche listbox et comme pour tous les widgets, tout en bas, dans les derniers paragraphes, il y en a un qui s'appelle DEFAULT BINDING


    Citation Envoyé par Cemalatowilo Voir le message
    2) Si j'ai bien compris toute variable écrite en majuscule dans tkinter (comme NUMBERS) est automatiquement une variable globale. Il n'est pas nécessaire de la passer en paramètres dans les déclaration de classe. très partique.
    NUMBERS n'est pas une variable "tkinter", c'est une variable que j'ai créé au tout début du programme: c'est la liste des nombres de 0..29.
    Les "variables" tkinter (END, FLAT, GROOVE) deviennent globales par la magie de from tkinter.constants import *.
    Les majuscules sont là pour signaler que ce sont des constantes.
    note: j'ai du oublié de remplacer "flat" et "groove" par les constantes "normales".

    NUMBERS et LINES auraient pu être passées en paramètres. C'était des variables globales dans la première mouture que vous avez réalisé et c'est resté comme çà. Cà ne me semblait pas essentiel (tant qu'elles restent des constantes).

    - W

  12. #32
    Membre du Club
    Homme Profil pro
    Retraité
    Inscrit en
    Septembre 2013
    Messages
    91
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2013
    Messages : 91
    Points : 52
    Points
    52
    Par défaut
    Honte à moi, j'ai oublié le principe des espaces de nom.
    Pour ma décharge, cela fait longtemps que j'avais programmé en POO.
    Merci pour vos temps passé avec moi, je passe le sujet en résolu.

Discussions similaires

  1. [RAVE] Comment visualiser un texte enrichi ?
    Par ARDILLER dans le forum Composants VCL
    Réponses: 4
    Dernier message: 14/03/2006, 15h54
  2. Réponses: 7
    Dernier message: 22/02/2006, 17h07
  3. Comment savoir quelle fenêtre possède le focus ?
    Par WebPac dans le forum API, COM et SDKs
    Réponses: 4
    Dernier message: 22/12/2005, 09h59
  4. [SWiSHMax] Comment visualiser un preloader en local
    Par 3psilOn dans le forum Flash
    Réponses: 1
    Dernier message: 22/07/2005, 15h43
  5. [Label] Comment faire clignoter un label ?
    Par delphicrous dans le forum Composants VCL
    Réponses: 7
    Dernier message: 09/07/2004, 16h50

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