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 :

Système de gestion des préférences


Sujet :

Python

  1. #1
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut Système de gestion des préférences
    Salut à tous !

    Je me lance dans un projet assez conséquent en python, et là j'essaie de mettre en place un système pour gérer les différentes options du programme.

    Par exemple, j'ai une classe qui charge automatiquement l'interface graphique depuis un fichier XML, et je voudrais pouvoir spécifier la taille des icônes des barres d'outils. Dans le __init__() de ma classe, j'ai donc un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    self.toolbar1.set_icon_size(taille)
    self.toolbar2.set_icon_size(taille)
    Le problème, c'est que si l'utilisateur veut pouvoir spécifier ultérieurement la taille de ces icônes, il faut que le prog arrive à retrouver une référence à 'toolbar1' alors qu'il est généralement en train d'exécuter une autre classe d'un autre fichier .py (=> plus de référence directe sur la toolbar)...


    Là je donne l'exemple d'une barre d'outils, mais le but du truc serait en fait de pouvoir modifier un attribut d'une classe depuis une autre.

    J'ai pensé à faire une classe 'PrefsManager' qui charge la config au démarrage et qui s'utiliserait de la sorte :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # fichier 1
    class InterfaceGraphique:
        def __init__(self):
            ...
            prefsmanager.appliquer_prefs_par_défaut(...)
            ...
     
    # fichier 2
    class Bidule:
            ...
            taille = demander_à_utilisateur()
            prefsmanager.appliquer_pref('toolbar_icon_size', taille)
            ...
    Ça c'est pour l'utilisation, mais ce qui m'intéresse évidement, c'est comment implémenter et configurer ce 'PrefsManager'...

    J'espère que vous comprenez le problème


    * * *

    Bon, là j'ai donné ma vision des choses, mais ce qui m'intéresse finalement, c'est comment VOUS vous y prenez pour gérer/appliquer les préférences utilisateurs dans un projet de ce type. Utilisez-vous un système centralisé (comme ce que j'essaie de mettre en place), ou autre chose ?

    Toute proposition/suggestion/critique est le bienvenue.
    Merci d'avance à tous ceux qui répondront

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    222
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 222
    Points : 290
    Points
    290
    Par défaut
    Je ne sais pas comment est fait ton programme, mais voici 2 propositions:

    Je pense que ta class bidule est instancier depuis InterfaceGraphique. Il suffit donc de passer l'instance de InterfaceGraphique à Bidule:

    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
     
    # fichier 1
    class InterfaceGraphique:
        def __init__(self):
            ...
            self.toolbar1.set_icon_size(taille)
            self.toolbar2.set_icon_size(taille)
            biduleInst = Bidule(self)
            ...
     
    # fichier 2
    class Bidule:
        def __init__(self, parent):
            self.parent = parent
     
        def changeconfig(self):
            taille = demander_à_utilisateur()        
            self.parent.toolbar1.set_icon_size(taille)
            self.parent.toolbar2.set_icon_size(taille)
    Moi en général je me sert de l'héritage.
    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
    # fichier 1
    class InterfaceGraphique:
        def __init__(self):
            Ici, uniquement ce qui est graphique
     
    # fichier 2
    class Bidule(InterfaceGraphique):
            def __init__(self):
                InterceGraphique.__init__(self)
                self.toolbar1.set_icon_size(taille)
                self.toolbar2.set_icon_size(taille)
     
            def onChangeConfig(self):
                taille = demander_à_utilisateur()        
                self.toolbar1.set_icon_size(taille)
                self.toolbar2.set_icon_size(taille)

  3. #3
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut
    C'est effectivement la solution la plus simple, mais elle n'est pas applicable dans mon cas (ou alors je m'y prends vraiment très mal... ).

    En effet, mes fichiers sont répartis dans plusieurs dossiers, un peu comme cela :
    ./monprog.py
    ./gui/__init__.py
    ./gui/customwidgets.py
    ./calcul/__init__.py
    ./calcul/einstein.py

    Ce que je voudrais, c'est par exemple pouvoir exécuter une fonction sur un objet dans la classe "Einstein" du module "einstein.py" depuis "customwidgets.py".

    Bref, d'un côté j'essaie d'être le plus modulaire possible en séparant bien les différentes fonctions de mon programme, et de l'autre j'ai un peu du mal à connecter tout ça...

  4. #4
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    222
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 222
    Points : 290
    Points
    290
    Par défaut
    Je ne suis pas sûr de bien comprendre.

    Pourquoi ne pas pas instancier ta classe Einstein dans customwidgets, Où faire hériter Monprog de customwidgets et de einstein?

    Enfin je pense qu'il y a quelque chose qui m'échappe.
    Qelle lib graphique utilises-tu?
    Pourrais tu donner un exemple de code plus ou moins fonctionnel?

  5. #5
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut
    J'utilise PyGTK.

    Dans la situation actuelle, la classe de base Monprog contiendra les instances de customwidgets et d'einstein.

    Évidemment, il faudra passer des données en référence aux classes, mais j'essaie de m'arranger pour avoir à en passer le moins possible (je veux pas de fonction __init__ () à 36 arguments), et pour automatiser au maximum les préférences.

    Si tu veux voir mon code :
    http://code.google.com/p/euphorbia/s...owse/?r=v0.0.3
    (c'est encore très brouillon, je suis en phase de tests)


    Un des buts est notamment de pouvoir générer un panneau de configuration automatiquement depuis les préférences. Par exemple, si tu regardes le fichier "prefs/__init__.py", j'ai défini au début une sorte de prototype de préférence, avec les valeurs possibles dans une liste (ou un dictionnaire) ; le prog affichera alors une liste déroulante permettant de choisir le valeur, et la fonction correspondante sera alors automatiquement appelée.


    -

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

    Là je donne l'exemple d'une barre d'outils, mais le but du truc serait en fait de pouvoir modifier un attribut d'une classe depuis une autre
    En Python on peut tout faire, mais pour que la modification soit effectivement prise en compte par les objets correspondants, il me semble nécessaire (au moins) que les attributs correspondants soient définis - puisqu'ils exigent un traitement particulier - et que l'objet correspondant soit informé que la valeur à été mise à jour.
    => les signals/slots de GTK peuvent très bien faire l'affaire à défaut d'utiliser un pattern observer.

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

  7. #7
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Voilà mon idé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
    # module prefs.py
    __all__ = ['prefsmanager']
     
    class _PrefsManager:
        # à ne pas instancer en-dehors de ce module
        def __init__(self):
            self.ui = None
     
        def initialize(self, ui):
            self.ui = ui
            self.prefs = load_default_prefs(...)
            self.apply_prefs()
     
        def apply_prefs(self):
            ...
            self.ui.toolbar1.set_icon_size(self.prefs['toolbar_icon_size'])
            ...
     
        def set_pref(self, name, value):
            # ajouter validation de name & value
            self.prefs[name] = value
     
    prefsmanager = _PrefsManager()
     
     
    # module gui.py
    from prefs import prefsmanager
     
    class InterfaceGraphique:
        def __init__(self):
            ...
            prefsmanager.initialize(self)
     
     
    # module bidule.py
    from prefs import prefsmanager
     
    ...
    prefsmanager.set_pref('toolbar_icon_size',16)
    ...
    presmanager.apply_prefs()
    ...
    Avec le mécanisme des import, la variable prefsmanager, globale au module prefs, ne sera créée qu'une seule fois et fera donc référence au même objet dans tout module qui l'importe.

    disclaimer: je n'y connais rien à GTK...

  8. #8
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Une autre idée.

    Dans une application, actuellement en développement, je me suis attaché à offrir, à l'utilisateur, un maximum de possibilités de personnalisations.

    Pour cela, les options utilisateur sont sauvegardées dans un dictionnaire que
    l'utilisation du module pickle rend aisé à utilisé.

    Exemple :

    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
     
    import pickle
     
    class MainApp(object):
     
        ...
        self.user_opt = {}
        try:
            objfile = open("options", "r")
            self.user_opt = pickle.load(objfile)
            objfile.close()
        except:
            # premiere utilisation ou fichier corrompu
            # creation des options de base
            self.user_opt[1000] = (800, 600) # taille de fenetre
            self.user_opt[1001] = 48 # taille d'icone
            self.user_opt[1002] = 15 # nombre de dossiers recents
            ...
            objfile = open("options", "w")
            pickle.dump (self.user_opt, objfile)
            objfile.close()
    Ici self est l'instance de la classe principale du programme, celle qui démarre l'appli.
    Si cette classe est instanciée ici :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    if __name__ == "__main__":
        ...
        app = MainApp()
        info = Infos()
        tool = Tools()
        ...
    Cas classique, self.user_opt devient accessible dans les autres classes avec app.user_opt et, pour certaines boites de dialogue appelées par d'autres mécanismes, il suffit que ce dialogue ouvre le fichier "option", puisque celui-ci est toujours à jour.

    Lorsque l'utilisateur modifie une option de l'appli, un bouton, dans cette fenêtre de préférences (un onglet dans mon cas), devient valide, en cliquant sur ce bouton,

    l'option est modifiée dans le dico
    le dico est sauvé
    le changement est appliqué à l'interface

    Ce procédé permet aussi que les options utilisateur puissent être modifiées où que ce soit
    dans l'appli y compris les boites de dialogue.

    Simple et pratique.

    vincent

  9. #9
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Janvier 2007
    Messages : 329
    Points : 366
    Points
    366
    Par défaut
    Merci à tous pour vos réponses

    Je vais regarder tout ça en détail, et je vais essayer d'utiliser ces astuces dans mon projet si besoin.

    @wiztricks :
    Le coup de l'Observer Pattern est intéressant, mais les slots ne sont pas gérés en pygtk (seulement en gtkmm/c++ je crois), contrairement à pyQt.
    Ceci dit, ça pourrait être adapté pour certains paramètres, je vais voir ce que je peux faire.

    @dividee :
    Je connaissais pas "__all__", et ça à l'air bien pratique !

    @VinsS :
    Je comptais aussi utiliser cPickle pour la sauvegarde. La méthode pour avoir "app.user_opt" partout est bien pensée, même si je préfère éviter les variables globales ; je l'utiliserai si nécessaire.

    -

Discussions similaires

  1. Système de gestion des maps/évènements
    Par Despirithium dans le forum Développement 2D, 3D et Jeux
    Réponses: 8
    Dernier message: 15/11/2012, 22h21
  2. [2.x] Système de gestion des positions
    Par alexandre92100 dans le forum Symfony
    Réponses: 3
    Dernier message: 04/06/2012, 14h01
  3. Système de gestion des gardes pharmacie
    Par mechakiss dans le forum Cas d'utilisation
    Réponses: 7
    Dernier message: 07/02/2012, 18h17
  4. Gestion des préférences
    Par malgache dans le forum Android
    Réponses: 10
    Dernier message: 01/06/2011, 10h15

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