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 :

appeler une méthode d'une autre classe [QtGui]


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Femme Profil pro
    Ingénieur informatique scientifique
    Inscrit en
    Mai 2010
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur informatique scientifique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2010
    Messages : 313
    Par défaut appeler une méthode d'une autre classe
    Bonjour,
    je débute en PyQt et je bloque pour appeler une méthode d'une classe depuis une autre classe.
    Par exemple, mettons que j'ai créé avec QtDesigner une calculatrice très simple, générant au final un fichier calculatrice.py avec une classe Ui_Calculatrice.
    J'ai également un fichier main.py qui lance cette application et contient notamment ce code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class calculatrice(QGroupBox):
    	def __init__(self, parent=None):
    		#Initialisation
    		QGroupBox.__init__(self)
    		self.ui = Ui_Calculatrice()
    		self.ui.setupUi(parent)
     
    		#Creation d'un objet "calcul"
    		monCalcul = calcul.Calcul()
     
    		#Connexions signaux et slots
                    self.connect(self.ui.pushButtonEgal,SIGNAL("clicked()"),monCalcul.calculer_operation())
    Comme on le voit ici j'ai voulu utiliser une méthode "calculer_operation" de la classe Calcul, qui est définie dans un autre fichier "calcul.py".
    je crée donc une instance de Calcul() puis je veux appeler "calculer_operation" lorsque je clique sur un bouton "=".

    Ma classe Calcul est la suivante:
    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
    class Calcul:
    	def __init__(self, parent=None):
    		self.n1 = 0
    		self.n2 = 0
    		self.op = '+'
     
    	#Fonction de calcul
    	def calculer_operation(self):
    		self.n1 = self.ui.spinBoxNombre1.value()
    		self.n2 = self.ui.spinBoxNombre2.value()
    		self.op = self.ui.comboBoxOperation.currentText()
     
    		if self.op=='+':
    			self.ui.labelResultat.setText(str(n1+n2))
    		elif self.op=='-':
    			self.ui.labelResultat.setText(str(n1-n2))
    		elif self.op=='/':
    			self.ui.labelResultat.setText(str(n1/n2))
    		else:
    			self.ui.labelResultat.setText(str(n1*n2))
    Bien sûr cela ne fonctionne pas (j'ai l'erreur "Calcul instance has no attribute 'ui'").
    Car ici, par exemple avec la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    self.n1 = self.ui.spinBoxNombre1.value()
    le "self" de "self.n1" représente la classe Calcul et le "self" de "self.ui.spinBoxNombre1.value()" la classe "calculatrice"... (enfin je crois?)
    Comment différencier les deux?

    Je sais qu'il est inutile de créer cette classe "Calcul" et que je pourrai directement définir la méthode "calculer_operation" dans la classe calculatrice, mais c'est pour le principe: je voudrais pouvoir faire ce genre d'appel dans le vrai projet que je dois développer.

    Est-ce possible (ou est-ce que j'ai écrit n'importe quoi ^^') et sinon comment doit-on procéder?
    Merci d'avance pour votre aide.

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    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 741
    Par défaut
    Citation Envoyé par mokochan Voir le message
    le "self" de "self.n1" représente la classe Calcul et le "self" de "self.ui.spinBoxNombre1.value()" la classe "calculatrice"... (enfin je crois?)
    self est d'abord le premier argument de la méthode de l'instance appelée. Dans votre cas c'est: monCalcul car vous avez écrit monCalcul.calculer_operation.
    Notez que j'ai omis les ().

    monCalcul ne connaît pas ui.
    Une façon parmi d'autre pourrait être de le passer lors de la création de Calcul. Exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class calculatrice(QGroupBox):
    	def __init__(self, parent=None):
                    ...
    		self.ui = ...
    		...
     
    		#Creation d'un objet "calcul"
    		monCalcul = calcul.Calcul(ui)
    Puis dans "Calcul"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Calcul:
    	def __init__(self, ui, parent=None):
                 ...
                 self.ui = ui
    La méthode "calculer_operation" pourra alors récupérer l'objet adhoc dans self.ui.

    Comment différencier les deux?
    L'intérêt des classes est de permettre de découper son code et de le regrouper en différentes boîtes qui permettront de fabriquer des instances qui auront un comportement "semblable".
    Problème: ces boîtes sont étanches et le programme ne fonctionne que si on agence des échanges entre elles.
    Python n'est qu'un langage qui permet de construire classe et instances.
    Côté POO, c'est côté pattern de conception qu'il faut aller regarder. Ils sont indépendant du langage de programmation. Ils traitent de l'organisation des associations entre classes dans différents cas.
    La POO est "compliquée" indépendamment du langage utilisé.

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

  3. #3
    Membre éclairé
    Femme Profil pro
    Ingénieur informatique scientifique
    Inscrit en
    Mai 2010
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur informatique scientifique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2010
    Messages : 313
    Par défaut
    Bonjour,
    merci pour ta réponse, en effet je n'avais pas pensé à passer directement mon objet Ui_Calculatrice en paramètre lors de l'initialisation de Calcul!
    Cela fonctionne très bien et va me permettre d'organiser mon code comme je le souhaite.
    Finalement le code qui fonctionne est le suivant:

    main.py: Fonction __init__ de la classe calculatrice(QgroupBox):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def __init__(self, parent=None):
     
    		#Initialisation
    		QGroupBox.__init__(self)
    		self.ui = Ui_Calculatrice()
    		self.ui.setupUi(parent)
     
    		#Creation d'un objet "calcul"
    		self.monCalcul = calcul.Calcul(self.ui)
     
    		#Connexions signaux et slots
    		self.connect(self.ui.pushButtonEgal,SIGNAL("clicked()"),self.monCalcul.calculer_operation)
    calcul.py:
    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
    class Calcul:
    	def __init__(self, ui, parent=None):
    		self.n1 = 0
    		self.n2 = 0
    		self.op = '+'
    		self.ui = ui
     
    	#Fonction de calcul
    	def calculer_operation(self):
    		self.n1 = self.ui.spinBoxNombre1.value()
    		self.n2 = self.ui.spinBoxNombre2.value()
    		self.op = self.ui.comboBoxOperation.currentText()
     
    		if self.op=='+':
    			self.ui.labelResultat.setText(str(self.n1+self.n2))
    		elif self.op=='-':
    			self.ui.labelResultat.setText(str(self.n1-self.n2))
    		elif self.op=='/':
    			self.ui.labelResultat.setText(str(self.n1/self.n2))
    		else:
    			self.ui.labelResultat.setText(str(self.n1*self.n2))
    Encore merci! J'avais l'habitude de faire des IHM en Perl/Tk, sans utiliser la POO, et je suis bien d'accord sur le fait que la POO est compliquée! Cependant cela permet de faire des codes lisibles et faciles à maintenir, cela vaut le coup de s'y attarder
    Bonne journée

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    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 741
    Par défaut
    Citation Envoyé par mokochan Voir le message
    Encore merci! J'avais l'habitude de faire des IHM en Perl/Tk, sans utiliser la POO, et je suis bien d'accord sur le fait que la POO est compliquée! Cependant cela permet de faire des codes lisibles et faciles à maintenir, cela vaut le coup de s'y attarder
    "lisibles et faciles à maintenir", c'est ce que raconte la plaquette marketing POO.
    Savoir organiser son code pour qu'il soit "lisible et facile à maintenir" est une sorte d'art: ce sont des qualités qui s'imposeront lorsque d'autres devront lire et modifier le code mais qui ne sont pas évidentes à fabriquer à priori. En tout cas, mettre des "class" partout n'est pas suffisant ni nécessaire.

    Illustration.
    Pour l'instant, "calculer_operation" dépend d'attributs de l'instance d'"Ui_Calculatrice" récupérée par "calculatrice". Une modification dans "Ui_Calculatrice" devra tenir compte de "calculatrice" pour ne rien casser.
    Cette dépendance pourrait être plus "lisible" si "calculer_operation" était méthode d"Ui_Calculatrice"
    Avec une simple fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def calculer_operation(n1, n2, op):
        if op=='+':
            return n1 + n2
        elif op=='-':
            return n1 - n2
        elif self.op=='/':
            if not n2: raise ValueError('divide by 0')
            return n1 / n2
        elif op == '*':
    	return n1 * n2
        raise ValueError('unknown op=%s' % op)
    vous pouvez tester que çà fonctionne sans l'UI.
    Et créer une méthode éponyme dans "calculatrice":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	def calculer_operation(self):
    		n1 = self.ui.spinBoxNombre1.value()
    		n2 = self.ui.spinBoxNombre2.value()
    		op = self.ui.comboBoxOperation.currentText()
                    try:
                          r = calculer_operation(n1, n2, op)
                    except ValueError:
                          pass
                    self.ui.labelResultat.setText(str(r))
    Cela permet de séparer l'action à exécuter de la récupération des informations à lui passer depuis l'interface utilisateur.
    Dans ce cas particulier, c'est simple mais imaginez une action plus "compliquée" à lancer depuis un autre dialogue utilisateur.
    Sans séparer mise en forme et traitement, c'est galère.

    La POO permet de faire des découpages comme le burin permet de casser des cailloux. Où donner le coup de burin pour ne pas exploser le caillou?
    "Séparer mise en forme et traitement" est un "principe d'organisation" qui peut aider ici POO ou pas.

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

  5. #5
    Membre éclairé
    Femme Profil pro
    Ingénieur informatique scientifique
    Inscrit en
    Mai 2010
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur informatique scientifique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Mai 2010
    Messages : 313
    Par défaut
    D'accord merci pour ces infos, je vais tâcher de faire une conception qui tient bien la route pour mon programme qui est assez complexe, en tenant compte de cette séparation traitement/mise en forme.
    Il y a juste une chose que je ne comprends pas:

    Cette dépendance pourrait être plus "lisible" si "calculer_operation" était méthode d"Ui_Calculatrice"
    Ui_Calculatrice est une classe créée par Qtdesigner dans un fichier calculatrice.py, je pensais qu'il fallait éviter de toucher aux code de ce genre de fichier? A moins que tu voulais dire de créer cette méthode dans la classe "calculatrice" et son éponyme dans la classe "Calcul"?

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    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 741
    Par défaut
    Salut,

    Citation Envoyé par mokochan Voir le message
    Ui_Calculatrice est une classe créée par Qtdesigner dans un fichier calculatrice.py, je pensais qu'il fallait éviter de toucher aux code de ce genre de fichier? A moins que tu voulais dire de créer cette méthode dans la classe "calculatrice" et son éponyme dans la classe "Calcul"?
    J'étais passé à côté de cela. Effectivement, il vaut mieux éviter de modifier ce qui sera généré automatiquement par QtDesigner.
    De fait, "Ui_Calculatrice" n'est pas complètement finalisée sortie de la chaîne de construction du QtDesigner: il manque des bouts.
    Il est donc possible de faire un import module as ui où module est le fichier généré via QtDesigner (il contient la définition de Ui_Calculatrice).
    Puis d'ajouter à Ui_Calculatrice les boûts qui manquent en créant une s/classe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Ui_Calculatrice(ui.Ui_Calculatrice):
    	def calculer_operation(self):
    		n1 = self.spinBoxNombre1.value()
    		n2 = self.spinBoxNombre2.value()
    		op = self.comboBoxOperation.currentText()
                    try:
                          r = calculer_operation(n1, n2, op)
                    except ValueError:
                          pass
                    self.labelResultat.setText(str(r))
    ...[/CODE]

    Un autre inconvénient dans les découpages est d'avoir à créer de nouveaux noms pour ajouter de tout petits trucs. Ré-utiliser les mêmes pour finaliser l'objet qui sera présenté/utilisé par le reste de l'application ou en trouver d'autres?

    L'idée est limiter les redirections dans l'expression "self.ui.spinBoxNombre1.value()" - visuellement les '.' - car value dépend de spinBoxNombre1 qui dépend de ui. Côté performances, c'est pas génial et en plus on s'enchaîne les dépendances.
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

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

Discussions similaires

  1. [PHP 5.3] [POO] Appel d'une méthode dans une méthode
    Par yann18 dans le forum Langage
    Réponses: 6
    Dernier message: 20/10/2011, 09h56
  2. Appeler une méthode d'une applet dans une jsp
    Par salmoucha10 dans le forum Applets
    Réponses: 1
    Dernier message: 11/01/2011, 19h25
  3. modifier un élément d'une form dans une méthode d'une autre form
    Par baldebaran dans le forum Windows Forms
    Réponses: 9
    Dernier message: 14/08/2009, 13h59
  4. Réponses: 10
    Dernier message: 28/05/2009, 09h29
  5. Réponses: 6
    Dernier message: 20/04/2007, 15h24

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