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

PyQt Python Discussion :

PyQt4 et les QStandardItemModel


Sujet :

PyQt Python

  1. #1
    Futur Membre du Club
    Inscrit en
    Août 2010
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 5
    Par défaut PyQt4 et les QStandardItemModel
    Bonjour à tous,

    Je viens vers vous car j'ai une question qui reste sans réponse.
    Tout d'abord je vous situe le contexte:

    Je programme un petit soft pour apprendre à "maîtriser" le python (j'utilise actuellement la version 2.7) et le superbe module PyQt4.

    Maintenant que le contexte est situé, voici mon problème:

    Mon interface graphique est constituée d'une main frame dans laquelle se trouve un Qwidget, lui même contenant d'autres widgets.
    Celui qui me pose problème est le QTreeView, pour gèrer l'affichage de mon arbre j'utilise le QStandartItemModel. Jusque là tout fonctionne comme je le souhaite!
    Mais je me suis mis en tête de pouvoir sauvegarde l'ensemble des labels, options désirées par l'utilisateur (moi) et le QStandardModel dans un fichier cfg! Pour faire cela, j'utilise la fonction Pickle.
    Chacune des variables est enregistrée dans un dictionnaire.

    Parfait les variables sont enregistrées, les labels aussi mais alors le QStandardItemModel est vide comme une coquille lui..voici ce que me donne le le fichier de config sur la partie concernant le modèle:


    Alors j'avais remarqué que l'on ne pouvait pas faire
    toto = QStandardItemModel()
    dupont = QStandardItemModel()

    toto = dupont

    Mais qu'il fallait insérer élément par élément le contenu du modèle vers un autre: alors c'est ce que j'ai fait, j'ai testé en faisant toto.clear() et puis MaFonctionCopie(toto, dupont). Mais ca ne fonctionne pas…

    J'ai essayé de sauvegarde le modèle seul… mis ca ne change rien! Maintenant je n'ai plus d'idées…J'ai regardé les exemples avec PyQt4.. Dans itemview.. Alors eux ils le font à partir d'un QRessource on dirait, mais n'ayant pas compris plus que ca l'exemple je préfère m'arrêter d'en parler

    Si l'un d'entre vous à une solution à me proposer, je suis preneur..

  2. #2
    Expert confirmé

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Salut, poste nous un bout de code significatif, que l'on puisse comprendre ce que tu cherche à obtenir.

    Moi, j'ai un peu de mal, qu'y-a-t-il dans ton treeView ? l'arborescence de ton pc ?

  3. #3
    Futur Membre du Club
    Inscrit en
    Août 2010
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 5
    Par défaut
    salut VinsS,
    je n'ai pas le code sous la main sur ce pc, je le posterai au plus tôt si jamais mes explications ne sont pas suffisantes:

    en faite je cherche à faire une liste des fichiers que je veux: je souhaite faire une sorte de petit IDE pour mes projets.
    il s'agit d'un arbre dans lequel j'affiche des .c et leur .h en fonctions de leur dépendance. Pas de soucis pour les faire afficher. J'inclus les éléments soit à la main soit de manière automatique.
    Ensuite je voulais pouvoir sauvegarder les options de configurations ainsi que l'arbre pour afficher là où j'en étais.
    Je sauvegarde les variables, les labels sans soucis! Mais la fonction cPickle ne permet pas de stocker des QStandardItemModel..

    Donc on m'a conseillé de le faire à la main..
    à la main j'arrive à sauvegarder le QStandardItemModel dans un autre modèle, sauvegarder les éléments de l'arbre dans deux dictionnaires: un pour les .c et un . les .h
    Chaque dictionnaire liste en faite les dépendances: exemple =>
    • dic["main.c"] = ['timer.h', 'interruptions.h']
    • dic["timer.c"] = ['timer.h', 'variables.h']
    • dic2['timer.h'] = ['interruptions.h', 'temps.h']


    c'est un exemple totalement inventé mais je pense que l'on comprend mieux.
    Je peux stocker ces dictionnaires à l'aide de la fonction cPickle dans un fichier: "config.tree' (encore une fois un exemple)
    et ensuite je les récupère.. j'ai encore quelques soucis car ma fonction qui est censé tout remettre sous forme d'arbre déconne au bout de deux dépendances.. (je fais des fonctions récursives de partout, c'est la mode dans mon code en ce moment).

    Est-ce plus compréhensible cette fois?

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Ptiloic Voir le message
    salut VinsS,
    je n'ai pas le code sous la main sur ce pc, je le posterai au plus tôt si jamais mes explications ne sont pas suffisantes:

    en faite je cherche à faire une liste des fichiers que je veux: je souhaite faire une sorte de petit IDE pour mes projets.
    il s'agit d'un arbre dans lequel j'affiche des .c et leur .h en fonctions de leur dépendance. Pas de soucis pour les faire afficher. J'inclus les éléments soit à la main soit de manière automatique.
    Ensuite je voulais pouvoir sauvegarder les options de configurations ainsi que l'arbre pour afficher là où j'en étais.
    Je sauvegarde les variables, les labels sans soucis! Mais la fonction cPickle ne permet pas de stocker des QStandardItemModel..

    Donc on m'a conseillé de le faire à la main..
    à la main j'arrive à sauvegarder le QStandardItemModel dans un autre modèle, sauvegarder les éléments de l'arbre dans deux dictionnaires: un pour les .c et un . les .h
    Chaque dictionnaire liste en faite les dépendances: exemple =>
    • dic["main.c"] = ['timer.h', 'interruptions.h']
    • dic["timer.c"] = ['timer.h', 'variables.h']
    • dic2['timer.h'] = ['interruptions.h', 'temps.h']


    c'est un exemple totalement inventé mais je pense que l'on comprend mieux.
    Je peux stocker ces dictionnaires à l'aide de la fonction cPickle dans un fichier: "config.tree' (encore une fois un exemple)
    et ensuite je les récupère.. j'ai encore quelques soucis car ma fonction qui est censé tout remettre sous forme d'arbre déconne au bout de deux dépendances.. (je fais des fonctions récursives de partout, c'est la mode dans mon code en ce moment).

    Est-ce plus compréhensible cette fois?
    Beaucoup plus compréhensible.

    Le problème, c'est que chacun à sa façon de programmer propre. Par exemple, si moi je devais faire ça, je mettrais
    - dans un module "modèle" tous les outils permettant de sauvegarder/restaurer les dépendances sur disque
    - dans un module "vue" ce qui permet d'afficher l'arbre (le QTreeWidget)
    - dans un module "contrôleur" l'arbre de mes dépendances à ma sauce (un peu comme tes dict)
    Si je dois sauvegarder l'arbre, je ne sauvegarde que mes dict. Des fonctions de bases permettront de stocker/charger ces dict sur disque. D'autres fonctions X ou Y auront pour charge d'afficher mes dict (sur un QTreeWidget éventuellement ou alors sur autre chose). L'avantage c'est que ce genre de programmation est hyper flexible
    1) si je veux, je rajoute une entrée clavier et l'intègre dans mes dict. Il sera affiché ensuite comme les autres par la fonction qui convertit les dict en QTreeWidget
    2) si je veux, je remplace la sauvegarde sur disque par une bdd de mon choix
    3) si un jour je veux changer d'IHM et remplacer Qt par wxWidget, je ne modifie que la partie "vue".
    etc etc. Cette méthode de découpage est ce qu'on appelle couramment le MVC (modèle/vue/contrôleur). Bref je ne base pas mon appli sur une seule technique/outil/lib...

    PS: fais gaffe à la mode. Une fonction récursive ça peut sembler la solution mais quand on sait tout ce qui se passe derrière... Ce n'est pas interdit bien entendu... mais si on peut éviter c'est un gain de temps à l'exécution.
    Exemple: les suites de Fibonacci
    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
    def fib_r(n):
       if n < 2: return 1
       return fib_r(n - 2) + fib_r(n - 1)
     
    def fib_i(n):
       res=[1, 1, 0]
       if n < 2: return res[n]
     
       i=2
       while i <= n:
           res[2]=res[0] + res[1]
           (res[0], res[1])=(res[1], res[2])
           i+=1
       return res[2]

    Voilà. La fonction récursive fait 2 lignes et l'itérative en fait 8. Mais compare donc les temps de réponse entre fib_r(38) et fib_i(38)...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Futur Membre du Club
    Inscrit en
    Août 2010
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 5
    Par défaut
    Je suis tout à fait d'accord cet objectif Sve@r
    J'avoue perdre un peu de temps en mélangeant ces 3 modules.. car je devrai obligatoirement tout reprendre.
    Mais bon j'ai quand même bien séparer tout ce qui concerne l'affichage et les données pour l'IHM (vive l'héritage multiple). D'où ma phrase: "j'apprend".. ca ne présentait pas d'utilités de tout séparer vu que je ne comprenait pas ce qu'il se passait.
    je pense que je vais refaire dès que j'aurais réussis à restaurer l'arbre!
    Histoire de mieux gérer l'affichage et les calculs.. ca me permettra de voir les threads en python au passage.

    Tu pourrais me montrer un petit exemple avec une fiction itérative s'il te plait? l'exemple du la suite de fibo ne me parle pas spécialement

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Ptiloic Voir le message
    Tu pourrais me montrer un petit exemple avec une fiction itérative s'il te plait? l'exemple du la suite de fibo ne me parle pas spécialement
    Mouais, si tu veux. Petite démo d'une création d'un arbre
    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
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
     
    # Objet pour gérer un noeud
    class cNode:
    	# Chaine d'affichage arborescence (static)
    	__arbo="|__"
     
    	# Constructeur
    	def __init__(self, libelle):
    		# On mémorise le libellé du noeud qu'on est en train de créer
    		self.__libelle=libelle
     
    		# Création de la branche fille
    		self.__depend=[]
     
    		# Le noeud créé est vierge donc il n'a pas de parent
    		self.__parent=None
    	# __init__()
     
    	# Ajout d'un noeud
    	def __append(self, node):
    		# On mémorise qu'on est le parent du noeud ajouté (pour l'instant le parent n'est pas utilisé mais c'est au cas où)
    		node.__parent=self
     
    		# On rajoute le nouveau noeud comme étant notre enfant
    		self.__depend.append(node)
    	# append()
     
    	# Fonction de recherche d'un noeud ayant un libellé particulier (récursive mais on peut pas faire autrement)
    	def __find(self, libelle, prof=0):
    		# Si le libellé demandé est le notre
    		if libelle == self.__libelle:
    			# Alors on est là
    			return self
     
    		# Balayage de la branche fille
    		for node in self.__depend:
    			# On récupère l'item correspondant au libellé cherché
    			item=node.__find(libelle, prof + 1)
     
    			# Si l'item a été trouvé
    			if item != None:
    				# On le renvoie à l'appelant
    				return item
    		# for
     
    		# La branche a été balayée - L'item n'a pas été trouvé
    		# Si on n'est pas au premier niveau
    		if prof != 0:
    			# Pas trouvé, le parent aura peut-être plus de chance dans une autre branche
    			return None
    		else:
    			# Pas trouvé et plus de parent => Erreur de clef
    			raise KeyError, libelle
    		# if
    	# __find()
     
    	# Opérateur [] pour affectation => permet d'écrire noeud[...]=noeud_fils
    	def __setitem__(self, libelle, fils):
    		# On recherche le noeud contenant le libellé
    		node=self.__find(libelle)
     
    		# Maintenant on va rajouter le noeud contenant le libellé dans la branche fille
    		node.__append(fils)
    		# On aurait pu écrire aussi self.__find(libelle).__append(fils)
    	# __setitem__()
     
    	# Opérateur [] pour récupération => permet de récupérer noeud[]
    	def __getitem__(self, libelle):
    		# On renvoie le noeud contenant le libellé
    		return self.__find(libelle)
    	# __getitem__()
     
    	# Affichage d'un noeud
    	def affich(self, prof=0):
    		# Création de la chaine d'affichage
    		string=""
     
    		# On affiche l'arbre
    		string+="%s" % self.__arbo * prof
     
    		# On affiche le libellé
    		string+="%s (%s)\n" % (self.__libelle, self.__parent.__libelle if self.__parent != None else "None")
     
    		# Traitement des fils
    		for item in self.__depend:
    			string+=item.affich(prof + 1)
     
    		# On renvoie la chaine
    		return string
    	# affich()
    # class cNode()
     
    # Création de l'arbre
    arbre=cNode("main.c")
     
    # Ajout d'une branche (marche grâce à "__setitem__")
    arbre["main.c"]=cNode("stdio.h")
    arbre["main.c"]=cNode("stdlib.h")
    arbre["stdlib.h"]=cNode("sys/types.h")
    arbre["stdlib.h"]=cNode("sys/socket.h")
    arbre["stdio.h"]=cNode("sys/base_stdio.h")
     
    # Affichage d'une branche (marche grâce à "__getitem__")
    print arbre["main.c"].affich()

    Tu remarqueras que le plus gros du travail est écrit dans la classe. Une fois qu'elle est bien écrite et bien robuste, l'utiliser devient trivial. Toutefois ce bref exemple n'est pas absolument parfait. On peut envisager aussi de définir l'objet "cArbre" ; même si c'est un objet ne contenant rien de plus qu'un noeud racine mais ce qui permettrait d'y inclure plus tard des outils en plus de manipulation/recherche/stats (évolutivité). Par exemple la fonction "__find" aurait plus sa place dans l'objet arbre que dans l'objet "noeud". Mais pour l'instant on peut considérer qu'un noeud est un mini arbre...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Futur Membre du Club
    Inscrit en
    Août 2010
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 5
    Par défaut
    très bon exemple!
    Je t'en remercie beaucoup!!
    Mais en faite je souhaitais avoir un exemple d'utilisation de fonctions itératives
    En tout cas, pour un script ton code ouvre vraiment plein de portes sur d'autres utilisations
    J'ai testé avec tn exemple, en essayant de l'adapter sur des QStandardItem 5éléments de l'arbre) et je me suis cassé les dents.. donc j'ai fait à la main. Le faite de travaille dans un modèle n'est pas considéré comme une dissociation de l'affichage et des données?

  8. #8
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Ptiloic Voir le message
    Mais en faite je souhaitais avoir un exemple d'utilisation de fonctions itératives
    Ben une fonction itérative c'est simplement une fonction qui n'est pas récursive. Le nom lui est donné ainsi car généralement, l'algorithme interne de la fonction comporte une boucle (itération) permettant de faire le travail demandé aussi bien (et certainement plus rapidement) que la fonction récursive.
    Exemple sur la factorielle:
    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def fact_r(n):
        if n == 0 or n == 1: return 1
        return n * fact(n - 1)
     
    def fact_i(n):
        if n == 0 or n == 1: return 1
        res=1
        for i in range(2, n + 1):
            res*=i      # Itération
     
        return res

    Citation Envoyé par Ptiloic Voir le message
    En tout cas, pour un script ton code ouvre vraiment plein de portes sur d'autres utilisations
    Le secret c'est l'objet. Un objet bien conçu, avec de petites méthodes très atomiques, qui font une action très simple, et ensuite ben tu fais ce que tu veux. Tu appelles juste la bonne méthode au bon moment quoi.

    Citation Envoyé par Ptiloic Voir le message
    J'ai testé avec tn exemple, en essayant de l'adapter sur des QStandardItem 5éléments de l'arbre) et je me suis cassé les dents.. donc j'ai fait à la main.
    Hé oui. C'est ma faute. Parce que je n'ai pas respecté à la lettre mon beau principe MVC et que j'ai intégré l'affichage (qui fait partie de la "vue") dans l'objet cNode (qui fait partie du "controleur").
    Et donc cette fonction "affich()" ne fait qu'afficher à l'écran ce qui est peu réutilisable. J'aurais dû faire plutôt un itérateur qui renvoie l'arborescence élément par élément. Ainsi, l'élément renvoyé peut être indifféremment traité par l'appelant (il l'enverra s'il le veut à l'écran, ou dans un QTreeWidget)

    Citation Envoyé par Ptiloic Voir le message
    Le faite de travaille dans un modèle n'est pas considéré comme une dissociation de l'affichage et des données?
    Sisi. C'est parce que Qt a lui aussi intégré le concept dans ses propres objets. Il a donc son propre modèle, le QStandardModel qu'il peut afficher dans ce que tu veux (un QTreeWidget ou un QTableWidget). C'est assez utile en C++ car ce langage est assez bas de gamme et offre peu de possibilités pour développer rapidement un modèle comme mon exemple (si j'avais dû l'écrire en C++ j'aurais mis 10x plus de temps) mais ça l'est moins en Python qui possède de beaux outils (les dict, les tuples, les list comprehension, les iterateurs) permettant de se programmer son propre modèle qu'on intègrera ensuite facilement dans un QTreeWidget. C'est pour ça qu'en Python, je me casse généralement pas le cul à passer par un QModel.

    Tiens, regarde cet exemple
    --- Fichier "node.py ---
    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
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
     
    # Objet pour gérer un noeud
    class cNode:
    	# Constructeur
    	def __init__(self, libelle):
    		# On mémorise le libellé du noeud qu'on est en train de créer
    		self.libelle=libelle
     
    		# Création de la branche fille
    		self.__depend=[]
     
    		# Le noeud créé est vierge donc il n'a pas de parent
    		self.parent=None
    	# __init__()
     
    	# Ajout d'un noeud
    	def __append(self, node):
    		# On mémorise qu'on est le parent du noeud ajouté (pour l'instant le parent n'est pas utilisé mais c'est au cas où)
    		node.parent=self
     
    		# On rajoute le nouveau noeud comme étant notre enfant
    		self.__depend.append(node)
    	# append()
     
    	# Fonction de recherche d'un noeud ayant un libellé particulier (récursive mais on peut pas faire autrement)
    	def __find(self, libelle, prof=0):
    		# Si le libellé demandé est le notre
    		if libelle == self.libelle:
    			# Alors on est là
    			return self
     
    		# Balayage de la branche fille
    		for node in self.__depend:
    			# On récupère l'item correspondant au libellé cherché
    			item=node.__find(libelle, prof + 1)
     
    			# Si l'item a été trouvé
    			if item != None:
    				# On le renvoie à l'appelant
    				return item
    		# for
     
    		# La branche a été balayée - L'item n'a pas été trouvé
    		# Si on n'est pas au premier niveau
    		if prof != 0:
    			# Pas trouvé, le parent aura peut-être plus de chance dans une autre branche
    			return None
    		else:
    			# Pas trouvé et plus de parent => Erreur de clef
    			raise KeyError, libelle
    		# if
    	# __find()
     
    	# Opérateur [] pour affectation => permet d'écrire noeud[...]=noeud_fils
    	def __setitem__(self, libelle, fils):
    		# On recherche le noeud contenant le libellé
    		node=self.__find(libelle)
     
    		# Maintenant on va rajouter le noeud contenant le libellé dans la branche fille
    		node.__append(fils)
    		# On aurait pu écrire aussi self.__find(libelle).__append(fils)
    	# __setitem__()
     
    	# Opérateur [] pour récupération => permet de récupérer noeud[]
    	def __getitem__(self, libelle):
    		# On renvoie le noeud contenant le libellé
    		return self.__find(libelle)
    	# __getitem__()
     
    	# Iterateur sur un noeud et tous ses fils (fonction récursive mais quand on traite des arbres, on peut pas faire autrement)
    	def get_node(self, prof=0):
    		# Renvoi d'un tuple contenant le noeud courant et sa profondeur
    		yield (self, prof)
     
    		# Traitement des fils
    		for item in self.__depend:
    			for (node, n) in item.get_node(prof + 1):
    				yield (node, n)
    		# J'ai eu du mal. Mais c'est que je suis pas encore très à l'aise avec les yield !!!
    	# get_node()
     
    	# Compteur du nb d'éléments d'un noeud (fonction récursive encore - j'ai l'air malin moi avec mes conseils d'éviter la récursivité !!!)
    	def count(self, deep=False):
    		# Si la profondeur est demandée
    		if deep:
    			# Initialisation compteur
    			cpt=0
     
    			# Traitement de tous les fils
    			for node in self.__depend:
    				cpt+=node.count(True)
    		else:
    			# On compte simplement le nb de fils
    			cpt=len(self.__depend)
     
    		# On renvoie le compteur (+ 1 car on est là nous aussi)
    		return cpt + 1
    	# cpt()
    # class cNode()
     
    # Pour tester la classe
    if __name__ == "__main__": 
    	# Création de l'arbre
    	arbre=cNode("projet")
     
    	# Ajout d'une branche
    	arbre["projet"]=cNode("main.c")
    	arbre["main.c"]=cNode("stdio.h")
    	arbre["projet"]=cNode("module.c")
    	arbre["module.c"]=cNode("sys/types.h")
    	arbre["module.c"]=cNode("sys/socket.h")
    	arbre["stdio.h"]=cNode("sys/types.h")
     
    	# Traitement de tous les noeuds
    	for (node, prof) in arbre["projet"].get_node():
    		print "%s%s (%s) - cpt=%d" % ("|__" * prof, node.libelle, node.parent.libelle if node.parent != None else "None", node.count(True))
    Donc ce module est déjà un petit exécutable à part entière. La seule différence, c'est que j'ai dissocié le controleur (la classe) de la vue (le print final). Maintenant, la classe ne fait que gérer le noeud et l'affichage se fait ailleurs (ici dans le "__main__"). Les membres parent et libelle ont été "déprivatisés" car ils ont maintenant besoin d'être vus depuis l'extérieur (on peut passer par un truc spécial pour éviter de déprivatiser les variables mais je me souviens plus donc j'ai pris un raccourci)

    Maintenant cet objet est 100% "pur controleur". Et donc si je veux, je peux aussi intégrer cet objet cNoeud dans un module "vue" (comme Qt) qui me permettra alors de savoir l'afficher à la mode de Qt

    --- Fichier "QtArbre.py" ---
    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
    150
    151
    152
    153
    154
    155
    156
    157
    158
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
     
    import sys
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    from node import cNode
     
    # L'application Qt
    class QtAppli(QApplication):
    	"Fenêtre de l'application"
     
    	# Constructeur fenêtre
    	def __init__(
    			self,
    			argv,
    			noeud):
     
    		# Message de contrôle
    		print "QtAppli (qt v%s, pyqt_v%s)" % (QT_VERSION_STR, PYQT_VERSION_STR)
     
    		# Appel constructeur de l'objet hértié
    		QApplication.__init__(self, argv)
     
    		# Attributs de l'application (c'est juste par habitude)
    		self.argv=argv
     
    		# Widget principale
    		self.wid=QMainWindow()
    		self.wid.setCentralWidget(QWidget(self.wid))
    		self.wid.statusBar()
     
    		# Titre
    		self.wid.setWindowTitle("Amusements avec Qt (v%s)" % QT_VERSION_STR)
     
    		# Un espace de rangement
    		layoutG=QVBoxLayout(self.wid.centralWidget())
    		layoutG.setMargin(5)
    		layoutG.setSpacing(5)
     
    		# L'arbre Qt créé à partir du noeud demandé
    		arbreQt=QtArbreProjet(noeud)
     
    		# Pour quitter
    		quit=QPushButton()
    		quit.setText("Quitter")
    		self.connect(quit, SIGNAL("clicked()"), self.wid, SLOT("close()"))
     
    		# Rangement des éléments dans le layout
    		layoutG.addWidget(arbreQt)
    		layoutG.addWidget(quit)
    	# __init__()
     
    	# Affichage et lancement application
    	def run(self):
    		self.wid.show()
    		self.exec_()
    	# run()
    # class QtAppli
     
    # Mon arbre perso
    class QtArbreProjet(QFrame):
    	# Constructeur arbre
    	def __init__(self, noeud):
    		# Appel constructeur de l'objet hértié
    		QFrame.__init__(self)
     
    		# Le schéma permettant de gérer les branches
    		self.__schema={}
     
    		# Un espace de rangement
    		layoutG=QVBoxLayout(self)
    		layoutG.setMargin(0)
    		layoutG.setSpacing(0)
     
    		# L'arbre proprement dit
    		self.__arbre=QTreeWidget()
     
    		# Une case à cocher
    		self.__deployCheck=QCheckBox(QString.fromUtf8("Déploiement"))
    		self.connect(
    			self.__deployCheck,
    			SIGNAL("stateChanged(int)"),
    			self.__slotDeploy,
    		)
     
    		# Rangement des éléments dans le layout
    		layoutG.addWidget(self.__arbre)
    		layoutG.addWidget(self.__deployCheck)
     
    		# Construction de l'arbre proprement dit
    		self.__construct(noeud)
    	# __init__()
     
    	# Nettoyage (si besoin)
    	def clear(self):
    		# Nettoyage de l'arbre et de son schema
    		self.__arbre.clear()
    		self.__schema={}
    	# clear()
     
    	# Construction de l'arbre à partir du noeud
    	def __construct(self, noeud):
    		# Nettoyage initial
    		self.clear()
     
    		# Le titre de l'arbre
    		self.__arbre.setHeaderLabel(QString.fromUtf8("%s (nb=%d)" % (noeud.libelle, noeud.count(True))))
     
    		# Traitement du noeur de base
    		for (node, prof) in noeud.get_node():
    			# Création de la branche
    			# Celle-ci est rattachée à la branche contenant le noeud parent (si existe) sinon à la racine de l'arbre
    			count=node.count() - 1
    			item=QTreeWidgetItem(
    				self.__schema[node.parent] if node.parent != None else self.__arbre,
    				QStringList(
    					QString.fromUtf8("%s%s" % (node.libelle, " (%d)" % count if count != 0 else ""))
    				),
    			)
     
    			# La branche créée est mémorisée dans le schéma (elle pourra ainsi servir de parente à une autre)
    			self.__schema[node]=item
    		# for
     
    		# Déploiement par défaut (éventuellement)
    		#self.__deployCheck.setChecked(Qt.Unchecked)
    	# __construct()
     
    	# Le slot qui gère le déploiement en fonction de la case cochée
    	def __slotDeploy(self, check):
    		# Etats possibles
    		state={
    			Qt.Checked : True,
    			Qt.Unchecked : False,
    		}
     
    		# Déploiement des branches en fonction de l'état de la case
    		[x.setExpanded(state[check]) for x in self.__schema.values()]
    	# __slotDeploy()
    # class QtArbreProjet
     
    # Pour tester la classe
    if __name__ == "__main__": 
    	# Création de l'arbre
    	arbre=cNode("projet")
     
    	# Ajout d'une branche
    	arbre["projet"]=cNode("main.c")
    	arbre["main.c"]=cNode("stdio.h")
    	arbre["projet"]=cNode("module.c")
    	arbre["module.c"]=cNode("sys/types.h")
    	arbre["module.c"]=cNode("sys/socket.h")
    	arbre["stdio.h"]=cNode("sys/types.h")
     
    	# Application Qt qui va afficher mon arbre
    	Appli=QtAppli(sys.argv, arbre["projet"])
    	Appli.run()

    Tu remarqueras ici aussi les petits découpages internes. J'aurais pu mettre le code de "__construct()" directement dans le "init". Mais je me dis que si plus tard j'ai besoin d'afficher plusieurs arbres différents (en fonction par exemple d'un choix supplémentaire), je serai alors bien content de pouvoir appeler et réappeler à volonté ma fonction __construct selon mon besoin. De même la méthode "clear" ne se justifie pas aujourd'hui mais qui sait demain...

    Et voilà un petit code sympa, modulaire et évolutif. Imagine qu'au lieu de créer l'arbre manuellement (les lignes finales arbre[xxx]=cNode(...)) cela pourrait être créé à partir d'un parse de ton makefile... ou à partir d'infos prises dans une bdd... ou carrément réutiliser cet objet pour afficher le contenu de ton disque dur

    --- Fichier "dir.py" ---
    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
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
     
    import os
    import stat
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    from node import cNode
    from QtArbre import *
     
    # Listing répertoire (récursif mais c'est maintenant devenu habituel: la récursivité c'est mal sauf quand c'est moi ;)
    def listdir(node, rep):
    	status=os.stat(rep)[stat.ST_MODE]
    	if stat.S_ISDIR(status)\
    		and not stat.S_ISLNK(status):
    		for file in os.listdir(rep):
    			node[node.libelle]=cNode(file)
    			listdir(node[file], "%s/%s" % (rep, file))
    	# listdir()
     
    if __name__ == "__main__": 
    	# Création de l'arbre à partir du disque dur
    	arbre=cNode("c:/windows")
    	listdir(arbre, arbre.libelle)
     
    	# Application Qt qui va afficher mon arbre
    	Appli=QtAppli(sys.argv, arbre)
    	Appli.run()

    Alors, t'en dis quoi ???
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  9. #9
    Futur Membre du Club
    Inscrit en
    Août 2010
    Messages
    5
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 5
    Par défaut
    je dis: chapeau , la classe !!! Ca me plaît, j'aime!
    Punaise c'est fou quand tu remarques tout ce que tu peux faire avec python.. et comme c'est agréable d'apprendre ce langage.

    En tout cas tu as super bien expliqué! j'ai lu et j'ai compris, enfin je pense
    Je vais me mettre dessus, tester, modifier, triturer.. et te faire un retour plus "critique" et discuter un peu de ce que j'ai fait.

    Si jamais tu n as pas de nouvelles pdt quelques jours, pas d'inquiétudes, je pars en vacances. Reposer le méninges..
    Mais là tu m'as exposé une vision assez différente de programmer de la mienne qui a plus de mal à exploiter la puissance des objets. Ca va m'empêcher de dormir... merci

    Je te remercie pour tes belles explications!

Discussions similaires

  1. Réponses: 29
    Dernier message: 25/03/2015, 07h29
  2. [QtGui] pyqt4, mainwindow,menubar: basculer les menus
    Par noramokh dans le forum PyQt
    Réponses: 9
    Dernier message: 13/07/2014, 14h09
  3. Réponses: 2
    Dernier message: 18/04/2012, 09h56
  4. Réponses: 20
    Dernier message: 12/12/2010, 21h25
  5. Obligatoire : lisez les règles du forum : MAJ 06/08/2010
    Par Anomaly dans le forum Mode d'emploi & aide aux nouveaux
    Réponses: 0
    Dernier message: 03/07/2008, 13h46

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