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

Python Discussion :

Problème de communication entre 2 class


Sujet :

Python

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Avril 2011
    Messages
    58
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Avril 2011
    Messages : 58
    Points : 39
    Points
    39
    Par défaut Problème de communication entre 2 class
    Bonjour,

    J'ai fait 3 class :

    - la class 'Detection_touche()'
    - la class 'Pane()' qui partage la fenêtre en 3 grâce à 'PanedWindow()'
    - la class 'Application()' qui devrait 'gérer' les 2 class précédentes

    Mais je n'arrive pas à 'récupérer' les touches détectées dans la class 'Application()' pour les mettre dans la fenêtre gauche.

    Plus exactement, j'ai essayé d'insérer la touche détectée dans la zone Text de la partie gauche avec la ligne : "f.gauche.insert(END, f)"

    Mais voila le seul message que j'obtiens dans la fenêtre gauche : "<__main__.Pane object at 0x02F739F0>


    Sauriez-vous comment faire pour qu'à chaque touche détectée je puisse afficher cette dernière dans la fenêtre gauche ?


    Voici le code :

    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
    from tkinter import *
     
     
    class Detection_touche(object):
     
        def __init__(self, boss):
            self.fen = boss
            self.flag = 'abc'
            self.fen.bind("<KeyPress>", self.Appui)
            self.fen.bind("<KeyRelease>", self.Relache)
     
     
        #L'appui prolongé sur une touche du clavier appelle plusieurs fois l'évenement
        #La variable "flag" permet d'intercepter le 1er évenement
        def Appui(self, event):
     
            flagTest = event.keysym
     
            if self.flag != flagTest:
                self.flag = flagTest
                print ("appui    : touche=",event.keysym)
            return(self.flag)
            return 'break'
     
     
        def Relache(self, event):
     
            print ("relache  : touche=",event.keysym)
            print('')
     
            self.flag = 'abc'
     
     
        def Resultat(self):
            print('Resultat = ',self.flag)
            return(self.flag)
     
     
    # Division de la fenetre en 3 "volets" redimensionnables
    class Pane(object):
     
        def __init__(self, boss):
            self.fen = boss
     
            # création 
            self.pane1 = PanedWindow(self.fen, showhandle=1, sashrelief=SUNKEN, orient=HORIZONTAL) ;# ou VERTICAL
            self.pane1.pack(expand='yes',fill="both")
     
            self.pane2 = PanedWindow(self.pane1, showhandle=1, sashrelief=SUNKEN, orient=VERTICAL)
            self.pane1.add(self.pane2)
            ##pane2.pack(expand='yes',fill="both")
     
            self.gauche = Text(self.pane2, bg="red")
            self.milieu = Text(self.pane1, bg="yellow")
            self.droite = Text(self.pane1, bg="white")
     
            self.pane2.add(self.gauche)
            self.pane1.add(self.droite)
            self.pane1.add(self.milieu)
     
     
    class Application(object):
     
        def __init__(self):
            self.Ecran = Tk()
            self.Ecran.geometry("300x150")
            f = Pane(self.Ecran)
            g = Detection_touche(self.Ecran)
            # récupération de la touche
            lambda f : g.Appui()
            # et insertion dans la zone texte 'gauche'
            f.gauche.insert(END, f)
            self.Ecran.mainloop()
     
     
    app = Application()

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 287
    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 287
    Points : 36 776
    Points
    36 776
    Par défaut
    Salut,
    Si vous écrivez - ligne 67 et +:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            f = Pane(self.Ecran)
            g = Detection_touche(self.Ecran)
            # récupération de la touche
            lambda f : g.Appui()
            # et insertion dans la zone texte 'gauche'
            f.gauche.insert(END, f)
    Alors le "f" en paramètre de f.gauche.insert est bien un objet qui ressemble à "<__main__.Pane object at 0x02F739F0>".
    Sauriez-vous comment faire pour qu'à chaque touche détectée je puisse afficher cette dernière dans la fenêtre gauche ?
    Je ne vois pas l'intérêt de découper le problème en "class":
    - la class 'Detection_touche()': encapsule les callbacks associés à des évènements Tk.
    - les class Pane et Application se réduisent au constructeur.

    "fenêtre gauche" doit correspondre à l'instance d'un widget Text.
    Les "actions" associées aux événements Tk devront la récupérer pour lui expédier des messages de mise à jour.
    Difficile de faire marcher un code du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            # récupération de la touche
            lambda f : g.Appui()
    Le problème n'est pas dans le lambda, mais tel que le code est écrit, la mise à jour de "fenêtre gauche" passe par l'exécution de "f.gauche.insert(END, f)".
    Comme cette instruction est dans le constructeur d'Application, il ne sera exécuté qu'une fois au démarrage.

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

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Avril 2011
    Messages
    58
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Avril 2011
    Messages : 58
    Points : 39
    Points
    39
    Par défaut
    Je ne vois pas l'intérêt de découper le problème en "class":
    - la class 'Detection_touche()': encapsule les callbacks associés à des évènements Tk.
    - les class Pane et Application se réduisent au constructeur.
    En fait, j'ai commencé de faire un script qui va contenir plusieurs centaines de lignes je pense et je voudrais le 'découper' en 'class' pour m'y retrouver plus facilement.


    Le problème n'est pas dans le lambda, mais tel que le code est écrit, la mise à jour de "fenêtre gauche" passe par l'exécution de "f.gauche.insert(END, f)".
    Comme cette instruction est dans le constructeur d'Application, il ne sera exécuté qu'une fois au démarrage.
    Je comprends; ça fonctionne effectivement bien lorsque le 'panneau' gauche est créé directement dans la class Detection_touche() puisqu'il peut être 'rafraîchi' à chaque détection d'une touche :


    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
    from tkinter import *
     
     
    class Detection_touche(object):
     
        def __init__(self, boss):
            self.fen = boss
            self.flag = 'abc'
            # Création des 3 panneaux de la fenêtre principale
            self.f = Pane(self.fen)
            self.fen.bind("<KeyPress>", self.Appui)
            self.fen.bind("<KeyRelease>", self.Relache)
     
     
        #L'appui prolongé sur une touche du clavier appelle plusieurs fois l'évenement
        #La variable "flag" permet d'intercepter le 1er évenement
        def Appui(self, event):
     
            flagTest = event.keysym
     
            if self.flag != flagTest:
                self.flag = flagTest
                print ("appui    : touche=",event.keysym)
                # Affichage de la touche 'en appui' dans le panneau de gauche
                self.f.gauche.insert(END, 'appui : ' + self.flag + '\n')
            return 'break'
     
     
        def Relache(self, event):
     
            # Affichage de la touche 'en appui' dans le panneau de gauche
            self.f.gauche.insert(END, 'relache : ' + self.flag + '\n')
            print ("relache  : touche=",event.keysym)
            print('')
            self.flag = 'abc'
     
     
     
    # Division de la fenetre en 3 "volets" redimensionnables
    class Pane(object):
     
        def __init__(self, boss):
            self.fen = boss
     
            # création 
            self.pane1 = PanedWindow(self.fen, showhandle=1, sashrelief=SUNKEN, orient=HORIZONTAL) ;# ou VERTICAL
            self.pane1.pack(expand='yes',fill="both")
     
            self.pane2 = PanedWindow(self.pane1, showhandle=1, sashrelief=SUNKEN, orient=VERTICAL)
            self.pane1.add(self.pane2)
            ##pane2.pack(expand='yes',fill="both")
     
    ##        self.pane3 = PanedWindow(pane1, showhandle=1, sashrelief=SUNKEN, orient=VERTICAL)
    ##        self.pane1.add(pane3)
     
            self.gauche = Text(self.pane2, bg="red")
            self.milieu = Text(self.pane1, bg="yellow")
            self.droite = Text(self.pane1, bg="white")
     
            self.pane2.add(self.gauche)
            self.pane1.add(self.droite)
            self.pane1.add(self.milieu)
     
     
    class Application(object):
     
        def __init__(self):
            self.Ecran = Tk()
            self.Ecran.geometry("300x150")
            g = Detection_touche(self.Ecran)
            self.Ecran.mainloop()
     
     
    app = Application()
    Je vous remercie pour vos conseils wiztricks et je vous souhaite une bonne fin de week-end.

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

    Citation Envoyé par sancho.poncho Voir le message
    En fait, j'ai commencé de faire un script qui va contenir plusieurs centaines de lignes je pense et je voudrais le 'découper' en 'class' pour m'y retrouver plus facilement.
    "plusieurs centaines de lignes" peuvent se découper en modules, en class ou autres. Comme vous découvrez la programmation Tk et Python, vous ne savez pas encore quels sont les découpages plus adaptés à votre code.
    Un des intérêts de Python est qu'en codant 10 fois (çà se dit) plus vite qu'avec un langage "compilé", vous pouvez repenser le design au fur et à mesure.

    Je ne sais pas ce que vous voulez faire mais en gros l'histoire se ramène à déclencher une action lorsque l'utilisateur appuie ou relâche une clé du clavier. Vous ne savez pas encore trop l'action à déclencher. Plutôt que d'utiliser la possibilité de trace des variable Tk, on peut fabriquer une "class" Event qui aura deux méthodes: .register et .signal.
    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
    class Event:
        def __init__(self):
            self._callbacks = []
     
        def register(self, cb):
            if cb not in self._callbacks:
                self._callbacks.append(cb)
     
        def signal(self, *args, **kwds):
            callbacks = self._callbacks[:]
            for cb in callbacks:
                try:
                    cb(*args, **kwds)
                except Exception as e:
                    print (e)
                    self._callbacks.remove(cb)
    En l'état, c'est un code plutôt "sale". Si le "callback" est méthode d'une instance, il faut passer par des weakref pour permettre au GC de faire son boulot après la destruction de l'instance. Mais çà joue sur le code réalisé dans les méthodes .register et .signal sans changer (à priori) l'interface: on dira que c'est "good enough" débuter.

    Après il faut gérer l'état des keysyms.
    En première approximation, on peut dire qu'au départ, toutes les keys sont "Released". La première action sera "Press" suivit plus tard d'un "Release".
    De fait, l'action pourrait être un appel à toggle(keysym) qui gère l'état des différentes keys. On peut représenter cet état par un dict dont les clés sont les keysym et les valeurs un booléen intialisé à False.

    L'un dans l'autre, çà donne:
    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
    class KeyState(dict):
        def __missing__(self, key):
            dict.__setitem__(self, key, False)
        def set(self, key, value):
            dict.__setitem__(self, key, value)
    key_state = KeyState()
     
    key_release = Event()
    key_press = Event()
     
    def toggle(key):
        state = key_state.get(key)
        if state:
            print ('key: %s is toggled On => Off' % key)
            key_release.signal(key)
        else:
            print ('key: %s is toggled Off => On' % key)
            key_press.signal(key)
        key_state.set(key, not state)
    Après, il faut tester que la mécanique fait ce qu'on attend d'elle:
    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
    if __name__ == '__main__':
     
        app = tk.Tk()
        app.geometry("300x150")
        app.event_add('<<ToggleKey>>', '<KeyPress>', '<KeyRelease>')
        app.bind('<<ToggleKey>>', lambda e: toggle(e.keysym))
     
        text = tk.Text(app)
        text.pack(fill='both', expand=True)
     
        def insert_key(text, keysym):
            text.insert('end', keysym)
     
        key_press.register(lambda key, text=text: insert_key(text, key))
     
        tk.mainloop()
    Cela fait, on voit bien que ce qui tourne autour de toggle et d'Event ne sont pas du même acabit. On aurait envie de les "grouper" dans des boîtes différentes. Il est encore trop tôt pour répartir ces choses en "modules" mais on peut faire "comme si" avec un peu de code.
    L'idée est d'encapsuler ces déclarations dans des "closures". A la base ce sont des "fonctions" mais on va geler leur état. Pour ce qui nous intéresse l'état sera le locals() de la fonction que j'emballe dans une "classe" pour préserver la syntaxe "dotted_name".
    L'ajout de cet emballage conduit à ce code:

    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
    registry = dict()
     
    def fake_module(name, ns, keys=None):
        '''helps to encapsulate state into something between module and class'''
        keys = (name, ) if keys is None else tuple( [ name ] +  list(keys))
        m = registry.get(keys)
        if m is None:
            ns.update({ k: staticmethod(v) for k, v in ns.items() if callable(v) })
            m = type(name, (object,), ns)
            registry[keys] = m
        return m
     
    def helpers():
     
        class Event:
            def __init__(self):
                self._callbacks = []
     
            def register(self, cb):
                if cb not in self._callbacks:
                    self._callbacks.append(cb)
     
            def signal(self, *args, **kwds):
                callbacks = self._callbacks[:]
                for cb in callbacks:
                    try:
                        cb(*args, **kwds)
                    except Exception as e:
                        print (e)
                        self._callbacks.remove(cb)
     
        return fake_module('helpers', locals())
     
     
    def keystate():
        h = helpers()
     
        class KeyState(dict):
            def __missing__(self, key):
                dict.__setitem__(self, key, False)
            def set(self, key, value):
                dict.__setitem__(self, key, value)
        key_state = KeyState()
     
        key_release = h.Event()
        key_press = h.Event()
     
        def toggle(key):
            state = key_state.get(key)
            if state:
                print ('key: %s is toggled On => Off' % key)
                key_release.signal(key)
            else:
                print ('key: %s is toggled Off => On' % key)
                key_press.signal(key)
            key_state.set(key, not state)
     
        return fake_module('keystate', locals())
     
    if __name__ == '__main__':
        import tkinter as tk
     
        ks = keystate()
     
        app = tk.Tk()
        app.geometry("300x150")
        app.event_add('<<ToggleKey>>', '<KeyPress>', '<KeyRelease>')
        app.bind('<<ToggleKey>>', lambda e: ks.toggle(e.keysym))
     
        text = tk.Text(app)
        text.pack(fill='both', expand=True)
     
        def insert_key(text, keysym):
            text.insert('end', keysym)
     
        ks.key_press.register(lambda key, text=text: insert_key(text, key))
     
        tk.mainloop()
    On peut encore améliorer la chose avec des décorateurs. Le but était de faire des variations sur les découpages de code en boîtes autres que "class".

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

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Avril 2011
    Messages
    58
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Avril 2011
    Messages : 58
    Points : 39
    Points
    39
    Par défaut
    Ouah, merci beaucoup pour vos explications sur les méthodes pour découper du code !

    Je perçois que, outre la souplesse du langage, la façon même d'agencer le code est riche en Python mais je n'ai pas un savoir suffisant pour saisir les subtilités de ce niveau-là... en tout cas pas avant un an ou deux

    Je vous remercie vraiment pour cette analyse détaillée des différentes méthodes de découpage du code et je reviendrai comprendre toutes vos explications dans quelques temps après avoir pratiquer suffisamment Python.

    Je vous souhaite une très bonne semaine wiztricks !

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

    Citation Envoyé par sancho.poncho Voir le message
    Je perçois que, outre la souplesse du langage, la façon même d'agencer le code est riche en Python mais je n'ai pas un savoir suffisant pour saisir les subtilités de ce niveau-là... en tout cas pas avant un an ou deux
    Si on réduit mon code à ce qu'il fait, çà se résume à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import tkinter as tk
     
    if __name__ == '__main__':
     
        app = tk.Tk()
        app.geometry("300x150")
     
        text = tk.Text(app)
        text.pack(fill='both', expand=True)
        app.bind('<KeyPress>', lambda e: text.insert('end', e.keysym))
     
        tk.mainloop()
    Ce "fonctionnel" a été multiplié par 5 ou 6 par le découpage que j'ai fait.
    C'est juste de l'overhead, du bavardage.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Avril 2011
    Messages
    58
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes de Haute Provence (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Avril 2011
    Messages : 58
    Points : 39
    Points
    39
    Par défaut
    Bonsoir wiztricks,

    Ce "fonctionnel" a été multiplié par 5 ou 6 par le découpage que j'ai fait.
    C'est juste de l'overhead, du bavardage.
    Développer le code, c'est justement ce qui me paraît le mieux pour comprendre comment il fonctionne.

    C'est peut-être du bavardage pour celui qui connait tout ça mais pas pour celui qui découvre ces concepts.

    Après, comme débutant, je n'ai pas le niveau suffisant pour tout comprendre; mais j'apprécie le geste.

    Bonne soirée wiztricks et merci encore pour le temps que vous avez consacré à me répondre.

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

Discussions similaires

  1. problème de communication entre mes classes
    Par emiliekun dans le forum ActionScript 3
    Réponses: 13
    Dernier message: 19/08/2009, 14h10
  2. Problème de communication entre classe
    Par FabaCoeur dans le forum Général Java
    Réponses: 4
    Dernier message: 22/01/2008, 13h50
  3. [c#] probléme de communication entre classe
    Par OpenGG dans le forum C#
    Réponses: 1
    Dernier message: 24/09/2006, 21h54
  4. Problème de communications entre threads
    Par maya09 dans le forum Windows
    Réponses: 1
    Dernier message: 22/02/2006, 22h18
  5. Réponses: 3
    Dernier message: 22/11/2005, 11h12

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