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 :

[POO] Interface graphique et grosse application (séparer la GUI et le "core" en deux classes distinctes) ?


Sujet :

Python

  1. #1
    Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Points : 45
    Points
    45
    Par défaut [POO] Interface graphique et grosse application (séparer la GUI et le "core" en deux classes distinctes) ?
    Salut à tous !

    EDIT 1 : Avant tout, je pense que c'est le bon forum, le problème n'étant pas l'interface graphique en elle même, mais plutôt l'écriture orienté objet de cette application, et certainement un problème d'héritage.

    Voilà, je me lance dans ma première grosse application à proprement parler.
    En la codant, je voudrais séparer un minimum l'interface graphique (wxPython) et les fonctions...
    Mais pour le moment, le choix de la GUI n'a pas trop d'importance, on pourrais autant le faire avec Tkinter, GTK...

    J'aimerais diviser ça en deux classe, une pour l'interface graphique, l'autre pour les actions.
    Mon problème est de faire communiquer les deux !

    Je vais donner un exemple "Hello World !" :

    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
    class GUI ():
        def __init__ (self):
            self.testUn = "Hello World !"
            self.bonjours()
            print self.testUn
     
        def bonjours (self):
            # --> Appel ici de l'autre classe (Test), en particulier la fonction fonctionTest.
     
    class Test ():
        def __init__ (self):
            pass
     
        def fonctionTest (self)
            # --> Récupération et affichage de self.testUn de la classe GUI
            # --> Modification de self.TestUn (self.testUn = "Coucou !")
     
    test = GUI()
    Je sais, c'est un peu ambigu, mais je ne vois pas comment faire autrement.
    En fait, mon programme en question, est un script pour supprimer les .DS_Store et les Thumb.db que Windows et Mac OS créent sur les clés USB...
    Et quand l'utilisateur va clique sur "Rechercher", "Supprimer"... La GUI doit appeler les fonctions de l'autre classe (recherche, supprimer...), sachant que cette dernière dois pouvoir lire et modifier des variables (récupérer le path pour la recherche...), widgets (ajouter les éléments trouvés à une liste...), etc... De la première classe qui gère la GUI.

    Je me dis que les gros programme doivent être séparé, la GUI d'un coté, et les fonctions du "core" de l'autre.
    J'ai essayer de regarder un "gros" programme en wxPython, pour voir comment c'est foutu dedans, mais en vain !

    Je pense qu'il s'agit de l'héritage.
    Mais je n'arrive pas à me représenter un tel schéma.

    J'en reviens donc à vous...
    Avez vous une idée de comment faire cette "chose ?

    Merci d'avance de m'éclairer !

    PS : Si vous avez besoin de plus de prècision, je peux essayer de vous en donner, mais c'est un peu flou pour moi aussi !



    EDIT 2 : Petit exemple en plus, pour faire plus clair...
    (Aucun rapport avec ce que je veux faire, maise la technique est la même !)
    Imaginons une fenêtre...

    2 widgets :
    - Champ de texte (valeur de départ --> 0).
    - Bouton "Go !"

    On clique sur le bouton, ça lance une méthode de la classe "core", qui fait une boucle jusqu'à 1000. A chaque passage de la boucle, la méthode doit modifier le champs de texte (qui est dans l'autre classe) et doit prendre la valeur actuel de la boucle.

  2. #2
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 751
    Points
    1 751
    Par défaut
    Bonjour,
    je ne comprends pas le problème. En fait, il faut faire un choix.

    A titre perso., je développe sur mon peu de temps libre un programme qui à partir de fichiers TXT va produire des PDF. Voilà ce que j'ai plainifié de faire :
    1. Le coeur du programme, que je finalise en ce moment, est un ensemble de classes, dites de production, qui vont produire les PDF à partir des fichiers TXT.
    2. Je vais ensuite faire une interface, non graphique, pour le terminal, ie pour un usage en ligne de commande. J'aurais donc un programme qui importera mes classes de production, et s'occupera de gérer les infos données dans le terminal pour produire ce qui doit l'être. Aucun surclassage à ce stade des classes de production.
    3. Pour finir, il y aura une interface graphique via PyQt. L'interface sera donc un ensemble de classes "graphiques" avec un éditeur graphique des fichiers TXT. Tout ce sera fait en PyQt.
      Au moment de produire les PDF, là j'appellerais mes classes de production. De nouveau, aucun surclassage à ce stade des classes de production.

    J'espère que cela t'aura éclairé un peu.

  3. #3
    Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Points : 45
    Points
    45
    Par défaut
    Oui, c'est une façon de voir les choses, en plus ça permet de faire tourner ce genre de programme sur des serveurs (pas d'interface graphique)...
    Mais mon problème c'est que je ne peux pas faire ça.

    J'ai une liste, et au fur et à mesure que la recherche s’effectue (thread), les résultats sont rajoutés à la suite de celle-ci.

    Sans même parler que la GUI est indispensable au cas ou qu'un fichier auquel on tiens se retrouve dedant (pour l'enlever des fichiers à supprimer).

    Donc si je sépare les deux... Les résultats ne serons pas affichés au fur et à mesure que les fichiers sont trouvés, mais d'une seule traite à la fin, sans donner d'indication à l'utilisateurs sur l'avancement.

    Mais merci quand même !
    Je trouve que ta méthode et super, je m'en servirais surement un de ces jour, mais malheureusement je ne pense pas que ce soit possible dans ce cas présent !

  4. #4
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 480
    Points : 9 277
    Points
    9 277
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    En ce qui me concerne, je considère que chaque fenêtre est représentée par une classe. Ce qui permet d'utiliser pleinement les mécanismes d'héritage.

    Comme chaque fenêtre graphique fonctionne par évènement (clavier, souris, etc...), TOUTES les méthodes gérant les évènements de la fenêtre sont bien entendu dans la classe de la fenêtre.

    Si ces méthodes appellent des traitements "lourds", rien n'empêche de déporter ces traitements dans une fonction ou une classe extérieure à la classe fenêtre, voire même dans des modules à importer.

    Par ailleurs, un programme complexe comportant plusieurs fenêtres peut très bien déporter dans un module séparé toute la "bibliothèque" des fonctions et classes commune à ces fenêtres. Mais sans jamais retirer de chaque classe fenêtre la "machinerie" de traitement de ses évènements.

    Bien entendu, il n'y a pas qu'une seule méthode possible pour structurer de grosses applications, mais il est important que la méthode choisie soit facile à construire, à comprendre et à maintenir dans le temps.

    Tyrtamos

  5. #5
    Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Points : 45
    Points
    45
    Par défaut
    Oui, voilà, c'est ça que je voudrais faire !
    Mais je ne sais pas comment m'y prendre afin que ça communique.

    Enfin, j'y ai réfléchis un peu depuis...
    J'en viens à la conclusion que la classe de la GUI, pour chaque évènement doit appeler une méthode d'une classe contenant tout mon "core", la classe de la GUI ne pouvant pas directement intervenir sur ce dernier, mais en revanche, lui peut intervenir sur la GUI.
    Ce serais donc mon "core" qui serais le parent et ma GUI l'enfant.

    Possible comme solution ?

    Merci tyrtamos !

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 347
    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 347
    Points : 36 870
    Points
    36 870
    Par défaut
    Salut,
    Allez sur Google ou sur le forum Conception et cherchez ce qui parle de MVC.
    Le M est le Model et correspond à votre "core".

    Je suis assez d'accord avec le parti de rambc: l'interface est une API de type commande qui pourrait être utilisée depuis d'autres scripts que l'IHM. Ca permet de concrétiser la séparation entre M et VC et de tester les deux indépendamment.
    Ceci dit rien ne vous oblige à une telle séparation, c'est à vous de voir.

    Il s'agit plus de composants que de classes - même si on construit des classes -. Un composant est une sorte de Singleton qui n'a de réalité qu'à travers les interfaces qu'il présente.
    Le lien est généralement l'aggrégation et non l'héritage.
    Ceci dit __getattr__ permet de rendre les choses plutôt transparentes.

    Je vous recommande d'aller voir les frameworks TraitsGUI et SIP qui permettent de réaliser des IHM indépendantes du GUI avec une séparation nette entre IHM et Model.
    Bon courage,
    - W

  7. #7
    Membre actif
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 328
    Points : 240
    Points
    240
    Par défaut
    Salut,

    Je ne sais pas si j'ai bien compris la question, mais ce n'est pas un truc dans ce goût-là que tu veux faire ?

    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
    class GUI(wx.Dialog):
        def __init__(self, parent):
            wx.Dialog.__init__(self, parent, -1)
            [...]
     
        def bonjours(self):
            print "coucou"
     
    class CORE(GUI):
        def __init__(self, parent):
            GUI.__init__(self, parent)
            self.fonctionTest()
     
        def fonctionTest(self) :
            GUI.bonjours()
    A +

  8. #8
    Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Points : 45
    Points
    45
    Par défaut
    En fait, la classe GUI doit pouvoir lancer les méthodes de la classe "core", et les méthodes de "core" doivent pouvoir modifier les widgets de la classe GUI.

    Imaginons une fenêtre...

    2 widgets :
    - Champ de texte (valeur de départ --> 0).
    - Bouton "Go !"

    On clique sur le bouton, ça lance une méthode de la classe "core", qui fait une boucle jusqu'à 1000. A chaque passage de la boucle, la méthode doit modifier le champs de texte (qui est dans l'autre classe) et doit prendre la valeur actuel de la boucle.

    Je pense que ce petit exemple est assez clair, je vais sans doute éditer mon premier post et le rajouter...

  9. #9
    Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Points : 45
    Points
    45
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Salut,
    Allez sur Google ou sur le forum Conception et cherchez ce qui parle de MVC.
    Le M est le Model et correspond à votre "core".

    Je suis assez d'accord avec le parti de rambc: l'interface est une API de type commande qui pourrait être utilisée depuis d'autres scripts que l'IHM. Ca permet de concrétiser la séparation entre M et VC et de tester les deux indépendamment.
    Ceci dit rien ne vous oblige à une telle séparation, c'est à vous de voir.

    Il s'agit plus de composants que de classes - même si on construit des classes -. Un composant est une sorte de Singleton qui n'a de réalité qu'à travers les interfaces qu'il présente.
    Le lien est généralement l'aggrégation et non l'héritage.
    Ceci dit __getattr__ permet de rendre les choses plutôt transparentes.

    Je vous recommande d'aller voir les frameworks TraitsGUI et SIP qui permettent de réaliser des IHM indépendantes du GUI avec une séparation nette entre IHM et Model.
    Bon courage,
    - W
    J'ai regardé du côté des MVC.
    J'ai trouvé ça:
    http://dosimple.ch/articles/Python-PyQt/

    Est-ce bien la même chose ?
    Serais t'il trop demandé qu'un petit exemple simplifié ?

    Merci wiztricks !

  10. #10
    Membre actif
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    159
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 159
    Points : 224
    Points
    224
    Par défaut
    Citation Envoyé par Darel Voir le message
    En fait, la classe GUI doit pouvoir lancer les méthodes de la classe "core", et les méthodes de "core" doivent pouvoir modifier les widgets de la classe GUI.

    Imaginons une fenêtre...

    2 widgets :
    - Champ de texte (valeur de départ --> 0).
    - Bouton "Go !"

    On clique sur le bouton, ça lance une méthode de la classe "core", qui fait une boucle jusqu'à 1000. A chaque passage de la boucle, la méthode doit modifier le champs de texte (qui est dans l'autre classe) et doit prendre la valeur actuel de la boucle.

    Je pense que ce petit exemple est assez clair, je vais sans doute éditer mon premier post et le rajouter...
    Pourquoi donner à une méthode de Core la responsabilité de modifier un élément de Gui ?
    Avant de commencer à envoyer des signaux dans tous les sens, il faut bien séparer comme conseillé plus haut ce qui relève du modèle et ce qui relève de la vue.

    Pour moi :
    Les méthodes de Core effectuent des calculs, et renvoient des données.
    Les méthodes de Gui appellent les méthodes de Core et affichent les données retournées.

    Dans ton exemple ci-dessus, il faut donc placer la boucle dans la méthode de Gui (puisque l'affichage est modifé à chaque tour, et que l'affichage est de la responsabilité de ton Gui).
    Core, elle, va fournir un itérateur sur lequel Gui pourra boucler.

    Par exemple : (ma "Gui" se contente de faire des print en console)

    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
     
    class Core:
        def __init__(self):
            self.counter = self._make_counter(0, 10)
     
        def _make_counter(self, start, end):
            x = start
            while x < end:
                yield x
                x += 1
     
    class Gui:
        def __init__(self):
            self.lib = Core()
     
        def count(self):
            for i in self.lib.counter:
                print i
     
    def main():
        gui = Gui()
        gui.count()
        return 0
     
    if __name__ == '__main__':
        main()

  11. #11
    Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Points : 45
    Points
    45
    Par défaut
    Ok !
    Je vais essayer de faire comme ça.
    C'est vrais que c'est plus propre, une GUI et un Core séparé.
    Merci beaucoup valAa pour ce petit exemple !

    Après si quelqu'un à plus d'explication sur le MCV, ça m'intéresse aussi...
    Encore merci à tous !

  12. #12
    Membre actif
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    328
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 328
    Points : 240
    Points
    240
    Par défaut
    Je crois franchement que c'est avec l'héritage dont je te donnais l'exemple plus haut que tu auras le code le plus propre et le plus simple

  13. #13
    Membre expérimenté Avatar de pacificator
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 074
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 074
    Points : 1 728
    Points
    1 728
    Par défaut
    un peu de lecture (en anglais) sur le MVC appliqué à wxpython.

  14. #14
    Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Points : 45
    Points
    45
    Par défaut
    Plutôt le contraire...
    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
    class CORE():
        def __init__(self):
            self.secret = 'Hello World !'
     
        def fonctionTest(self) :
            return self.secret
     
    class GUI(wx.Dialog, CORE):
        def __init__(self, parent):
            wx.Dialog.__init__(self, parent, -1)
            CORE.__init__(self)
            [...]
     
        def Test (self):
            print CORE.fonctionTest()
    Au moins, la classe GUI peut accéder au méthodes et aux arguments de la classe Core...
    Et la classe Core ne contient rien de l'IHM.
    Ainsi, la classe GUI ne gère que l'IHM et les données, et la classe Core que les opérations de base de l'application.

    On a donc la Vue et le Contrôleur. (si j'ai bien compris )
    Mais où est le modèle ?

    Mais merci !
    J'ai déjà les idées beaucoup plus clair sur mon problème !

    EDIT : J'ai mis un "print" car j'ai la flemme de coder un wx.StaticText pour cet exemple, mais c'est tout comme !

  15. #15
    Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Points : 45
    Points
    45
    Par défaut
    Citation Envoyé par pacificator Voir le message
    un peu de lecture (en anglais) sur le MVC appliqué à wxpython.
    Je vais regarder ça !
    J'ai cherché, mais trouvé que pour PyQt !
    Merci pacificator !

  16. #16
    Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Points : 45
    Points
    45
    Par défaut
    Citation Envoyé par pacificator Voir le message
    un peu de lecture (en anglais) sur le MVC appliqué à wxpython.
    Splendide, rien à redire !
    J'ai trouvé la réponse à ma question :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    from wx.lib.pubsub import Publisher
    Un petit exemple maison :
    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
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    from wx.lib.pubsub import Publisher as pub
     
    class Riri ():
    	def __init__ (self):
    		self.name = 'My name is Riri !'
    		self.whoAreYou()
     
    	def whoAreYou (self):
    		pub.sendMessage('I WANT TO SPEAK', self.name)
     
    class Fifi ():
    	def __init__ (self):
    		self.name = 'My name is Fifi !'
    		self.whoAreYou()
     
    	def whoAreYou (self):
    		pub.sendMessage('I WANT TO SPEAK', self.name)
     
    class Loulou ():
    	def __init__ (self):
    		self.name = 'My name is Loulou !'
    		self.whoAreYou()
     
    	def whoAreYou (self):
    		pub.sendMessage('I WANT TO SPEAK', self.name)
     
    class Test:
    	def __init__ (self):
    		pub.subscribe(self.reception, 'I WANT TO SPEAK')
     
    	def reception (self, message):
    		self.temp = message.data
    		print self.temp
     
    test = Test()
     
    riri = Riri()
    fifi = Fifi()
    loulou = Loulou()
    Résultat :
    My name is Riri !
    My name is Fifi !
    My name is Loulou !
    Voilà, j'ai donc réussit à faire communique mes classes entre elles.
    Je vais donc faire trois classes :
    1. Classe GUI
    2. Classe Core
    3. Classe Control

    La classe GUI et la Classe Core s'adresserons à la classe Control, qui servira de passerelle entre les deux.
    Elles ne pourront pas communiquer entre elles directement, seulement par l'intermédiaire de cette dernière.

    Si ça vous intéresse comme technique, sur Google avec "wx.lib.pubsub" ce ne sont pas les résultats qui manquent !
    Notamment (en Français) : http://afnarel.free.fr/index.php?pos...-module-pubsub

    Donc voilà, un grand merci à tous !
    Et un très grand merci à pacificator !

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

Discussions similaires

  1. Interfaces graphiques d'une application Java
    Par adil.boudaaoua dans le forum AWT/Swing
    Réponses: 2
    Dernier message: 05/04/2013, 15h38
  2. interface graphique d'une application
    Par hanou88 dans le forum C++Builder
    Réponses: 2
    Dernier message: 27/12/2009, 22h02
  3. interface graphique d'une application en c
    Par hanou88 dans le forum GUI
    Réponses: 3
    Dernier message: 28/11/2009, 23h34
  4. Réponses: 6
    Dernier message: 26/09/2007, 00h03
  5. Réponses: 3
    Dernier message: 15/06/2007, 18h14

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