Exécuter un code dans la méthode __init__ d'une classe, mais pas pour sa fille

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonsoir à tous,

J’essaie d’apprendre PyQt5, et je trouve la documentation assez mal faite, du coup je tatonne beaucoup. Je suis aussi un débutant en python, et en programmation de manière plus générale, ce qui sera évident à la lecture de ce qui suit.

J’essaie donc de faire une classe qui affiche la fenêtre principale, et une classe fille qui y ajoute quelque chose. Voici un exemple de code.

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, qApp, QWidget, QPushButton, QAction, QLineEdit, QMessageBox

class Main(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setUI()

    def setUI(self):
        self.setGeometry(100,100,1200,800)
        self.setWindowTitle('Fenêtre principale')
        self.show()

class AddSentence(Main):
    def __init__(self):
        super().__init__()
        self.setUIAdd()

    def setUIAdd(self):
        self.translationField=QLineEdit(self)
        self.translationField.move(400,300)
        self.translationField.resize(400,50)
        self.show()

monApp=QApplication(sys.argv)
fenetre=AddSentence()
sys.exit(monApp.exec_())

Ce qui se produit ici, c’est que le premier self.show() s’exécute (celui de la classe Main, et pas le second. Si j’enlève le premier, tout s’affiche comme je le veux, mais je ne peux plus créer un objet de cette classe qui afficherait quoi que ce soit.

Je me suis dit que ca ressemblait pas mal au if __name__ == "__main__":, mais je n’ai pas réussi à trouver d’équivalent pour les classes.

J’ai aussi essayer de jouer avec le mro, en ajoutant if(len(self.mro())<2): avant le premier self.show(), mais je ne dois pas bien comprendre le concept, puisque python m’indique que AttributeError: 'AddSentence' object has no attribute 'mro'.

Du coup, voici mes questions :

  1. Y a-t-il une manière spécifique de faire ce que je veux en python ? Si oui, quels seraient les mots clés à chercher, parce que je n’ai rien trouvé.
  2. Y a-t-il un moyen de forcer le self.show() à s’actuliser ? Mon problème serait résolu.
  3. Quelle est mon erreur avec le mro ?

Merci d’avance !

Auteur du sujet

Je voudrais que la classe fille ait l’UI de la mère et la sienne. Mais il semble qu’après le premier self.show(), le reste soit ignoré (ou au moins, pas affiché). Du coup je voudrais que le self.show() de la mère soit utilisé si je fais

fenetre=Main()

mais pas quand j’écris

fenetre=AddSentence()

Est-ce plus clair ? Je voudrais ignorer des lignes, mais seulement quand elles proviennent d’un héritage.

Je pense que la solution à privilégier serait d’appeler show en dehors de la classe, je ne trouve pas logique que la fenêtre s’affiche directement en instanciant l’objet.

Aussi, pourquoi avoir nommé ta méthode setUIAdd dans AddSentence et non setUI comme dans la classe mère ?

La meilleure façon serait en effet d’appeler show en dehors de ta classe. Une autre façon est de redéfinir setUI dans ta classe fille :

class AddSentence(Main):
    def __init__(self):
        super().__init__()
        self.setUIAdd()

    def setUI(self):
        self.setGeometry(100, 100, 1200, 800)
        self.setWindowTitle('Fenêtre principale')

    def setUIAdd(self):
        self.translationField = QLineEdit(self)
        self.translationField.move(400, 300)
        self.translationField.resize(400, 50)
        self.show()
+1 -0

Bonjour

Juste une petite remarque à propos de la documentation Si celle de PyQt ne te satisfait pas, n’hésites pas à aller sur celle de Qt.

Personnellement, je n’ai encore eu aucune difficulté pour "passer" du C++ en python: même nom de méthodes, souvent même types d’arguments (parfois on peut mettre du unicode lorsque la doc indique uniquement du QString)

+1 -0
Auteur du sujet

Merci pour vos réponses.

n’hésite pas à aller sur celle de Qt.

Merci, j’irai voir après le travail si cette documentation me convient mieux.

Aussi, pourquoi avoir nommé ta méthode setUIAdd dans AddSentence et non setUI comme dans la classe mère ?

Une autre façon est de redéfinir setUI dans ta classe fille 

Dans ce cas, je perds les bénéfices de l’héritage, non ? Je veux que tout ce qui est défini dans la méthode setUI classe mère soit utilisé (là j’ai simplifié, mais ça inclue un menuBar, des actions diverses (qui ne devraient peut-être pas être dans la méthode setUI, mais c’était comme ça dans l’exemple que j’avais trouvé)). Je compte avoir plusieurs classes filles, donc tout recopier va dupliquer le code pas mal. Il est également possible que je m’y prenne entièrement mal.

Je pense que la solution à privilégier serait d’appeler show en dehors de la classe

La meilleure façon serait en effet d’appeler show en dehors de ta classe.

Donc quelque chose comme

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, qApp, QWidget, QPushButton, QAction, QLineEdit, QMessageBox

class Main(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setUI()

    def setUI(self):
        self.setGeometry(100,100,1200,800)
        self.setWindowTitle('Fenêtre principale')

class AddSentence(Main):
    def __init__(self):
        super().__init__()
        self.setUIAdd()

    def setUIAdd(self):
        self.translationField=QLineEdit(self)
        self.translationField.move(400,300)
        self.translationField.resize(400,50)

monApp=QApplication(sys.argv)
fenetre=AddSentence()
fenetre.show()
sys.exit(monApp.exec_())

Je n’ai pas testé (pas python ici), mais dans le principe, c’est ce que vous me conseillez ? Il va falloir que je réfléchisse plus longtemps que je ne le peux ici pour comprendre les implications sur la construction des actions qui changent l’affichage (valider le translationField par exemple, qui devrait remettre un champ vide, et afficher la phrase entrée en dessous), mais je vais le garder à l’esprit et faire des tests.

Et je pense comprendre que la solution à base de mro n’est pas bonne, mais je ne comprends toujours pas pourquoi j’ai une erreur. J’ai un sentiment que ça vient d’une différenciation classe/instance de la classe, mais honnêtement, je n’en sais rien.

Merci encore !

Dans ce cas, je perds les bénéfices de l’héritage, non ? Je veux que tout ce qui est défini dans la méthode setUI classe mère soit utilisé (là j’ai simplifié, mais ça inclue un menuBar, des actions diverses (qui ne devraient peut-être pas être dans la méthode setUI, mais c’était comme ça dans l’exemple que j’avais trouvé)). Je compte avoir plusieurs classes filles, donc tout recopier va dupliquer le code pas mal. Il est également possible que je m’y prenne entièrement mal.

Rockaround

C’est tout le principe de super : permettre dans une classe fille de faire appel aux méthodes d’une parente. C’est ce que tu fais dans la méthode __init__ d'AddSentence.

Sauf que cette méthode __init__ n’apporte rien, tu pourrais très bien l’omettre et simplement redéfinir une setUI où tu ferais appel à la méthode parente.

Pour moi le code de la classe AddSentence devrait ressembler à :

class AddSentence(Main):
    def setUI(self):
        super().setUI()
        self.translationField=QLineEdit(self)
        self.translationField.move(400,300)
        self.translationField.resize(400,50)

Et je pense comprendre que la solution à base de mro n’est pas bonne, mais je ne comprends toujours pas pourquoi j’ai une erreur. J’ai un sentiment que ça vient d’une différenciation classe/instance de la classe, mais honnêtement, je n’en sais rien.

Rockaround

En effet, mro est une méthode qui existe sur la classe, pas sur ses instances.

Tu pourrais te dire que ce n’est pas logique, car les méthodes de classes sont censées être accessibles par les instances. Mais mro n’est pas une méthode de classe, c’est une méthode de type, qui est donc définie pour les instances de type. AddSentence est une instance de type, AddSentence() n’en est pas une.

>>> class A:
...     pass
... 
>>> a = A()
>>> 
>>> A.mro()
[<class '__main__.A'>, <class 'object'>]
>>> a.mro()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'mro'
>>> A.mro
<built-in method mro of type object at 0x5626f6a0bc38>
>>> type.mro
<method 'mro' of 'type' objects>
>>> type.mro(A)
[<class '__main__.A'>, <class 'object'>]

Édité par entwanne

Auteur du sujet

Merci encore pour les réponses. J’ai compris certaines choses, me si tout n’est pas encore clair (sur ce sujet précis hein? sur d’autres sujets, j’ai encore plein de questions :D ).

Ce que j’ai fait, en suivant vos conseils :

  • J’ai retiré les méthodes __init__ complètement.
  • J’ai nommé de la même manière les méthodes setUI des deux classes. Celle de la fille appelle celle de la mère.
  • J’ai retiré les self.show() de mes classes. À la place, dans mon code, après l’instanciation fenetre=AddSentence(), j’appelle la méthode fenetre.setUI(), et je continue avec fenetre.show()

Donc ma question initiale n’a pas eu de réponse directe, mais mon problème est résolu. Merci encore ! Reste pour moi à bien comprendre tout ca, et à comprendre comment mes méthodes clicked.connect(method) vont faire pour changer l’affichage.

Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte