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

GUI Python Discussion :

problème de connexion de boutons dans une GUI PyQt5 [Python 3.X]


Sujet :

GUI Python

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 13
    Points : 9
    Points
    9
    Par défaut problème de connexion de boutons dans une GUI PyQt5
    Bonjour à tous,

    J'ai conçu une application en utilisant PyQt5 et Qtdesigner. Je suis en train de la reconfigurer proprement en me basant sur le modèle MVC (Model View Controller). J'ai donc 3 fichier principaux:
    - view.py
    - controller.py
    - model.py

    Voici le code présent dans le controller.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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    class flex_ctrl():
     
        def __init__(self, model, view):
            self._model = model
            self._view = view
            self._connect_signals()
     
        def _load_file(self):
            print('i am loading')
            file_name = self._view.list_file.selectedIndexes()[0].data() + '.txt'
            print(file_name)
            self._model.set_data(file_name)
     
        def _new_file(self):
            print('new file')
     
        def _connect_signals(self):
            self._view.list_file.clicked.connect(self._view.able_button)
            self._view.load_button.clicked.connect(self._load_file)
            self._view.list_file.activated.connect(self._load_file)
            self._view.create_button.clicked.connect(self._new_file)
     
    def main():
        app = QApplication(sys.argv)
        view = f_v.flex_view()
        view.show()
     
        model = f_m.flex_core()
     
        flex_ctrl(model = model, view = view)
     
        app.exec()
     
    if __name__ == '__main__':
            main()
    f_v est le fichier view.py et f_m le fichier model.py. Ils contiennent respectivement une class flex_view (GUI) et flex_core (stockage données, traitement etc.).

    Mon problème est que : lorsque j'appuie sur les boutons de la GUI, rien ne se passe.

    self._view.list_file.clicked.connect(self._view.able_button)
    Cette ligne fonctionne très bien. Lorsque je clique sur un élement de la liste, le bouton change bien de couleur et il devient utilisable (but de la fonction able_button)

    En revanche, les lignes suivantes ne semblent pas fonctionner:
    self._view.load_button.clicked.connect(self._load_file)
    self._view.list_file.activated.connect(self._load_file)
    Lorsque que je double clique sur un élément de la liste ou bien que j'appuie sur le bouton concerné, aucune action ne se passe. Le texte "I am loading" ne s'affiche même pas, tout comme le texte "new file".

    En revanche, si je passe la fonction "_new_file" dans la classe flex_view et que je connecte donc le bouton à la méthode de la classe flex_view, tout va bien, le texte s'imprime.

    On dirait qu'il ne veut pas connecter les boutons de ma GUI aux fonctions de ma classe controller.

    Je me suis basé sur ce tutoriel là.

    Merci d'avoir pris le temps de me lire et surtout de m'aider

  2. #2
    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,

    Citation Envoyé par francky380 Voir le message
    Mon problème est que : lorsque j'appuie sur les boutons de la GUI, rien ne se passe.
    Quand vous avez ce genre de problème, votre premier travail sera de le reproduire sur un petit exemple qui permettra a ce qui essaieront de comprendre de le reproduire.

    A priori, votre code ne peut pas fonctionner parce que:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
               self._view.load_button.clicked.connect(self._load_file)
    Le "self" du self._load_file est l'objet créé ligne 30 par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    flex_ctrl(model = model, view = view)
    auquel vous ne gardez aucune référence. Il sera détruit et le connect ne va pas appeler la méthode d'un objet qui n'existe plus.

    Modifiez cette ligne avec:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    a = flex_ctrl(model = model, view = view)
    pour garder une référence et çà devrait fonctionner.

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

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 13
    Points : 9
    Points
    9
    Par défaut
    Wiztricks, merci beaucoup, la réponse est bien là !

    Tout d'abord, désolé pour le fait de ne pas avoir donnée un code reproductible. J'étais certains que l'erreur allait sauté au yeux d'un connaisseur, mais c'est une très mauvaise habitude à prendre, je le comprends.

    Enfin, pourquoi dans le tutoriel cela fonctionne, mais pas dans mon exemple? Dans le tutoriel il crée bien l'objet sans référence, comme moi, pourtant tout le code fonctionne correctement.

  4. #4
    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,

    Citation Envoyé par francky380 Voir le message
    Enfin, pourquoi dans le tutoriel cela fonctionne, mais pas dans mon exemple? Dans le tutoriel il crée bien l'objet sans référence, comme moi, pourtant tout le code fonctionne correctement.
    Il y a plein de codes dans ce tuto. certains bouts gardent une référence explicite, d'autres le font de façon implicite (et pas sûr que l'auteur sache faire la différence).

    Montrez le bout de code, et je vous dirais ce que j'en pense.

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

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 13
    Points : 9
    Points
    9
    Par défaut
    Le tutoriel tend à créer une calculatrice sous python en utilisant PyQt et le modèle MVC.
    Voici des extraits qui me semblent pertinents:

    l'objet "Model" est représenté uniquement par cette fonction. Ce n'est donc pas un objet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    ERROR_MSG = 'ERROR'
     
    # Create a Model to handle the calculator's operation
    def evaluateExpression(expression):
        """Evaluate an expression."""
        try:
            result = str(eval(expression, {}, {}))
        except Exception:
            result = ERROR_MSG
     
        return result
    l'objet controller:

    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
    class PyCalcCtrl:
        """PyCalc's Controller."""
        def __init__(self, model, view):
            """Controller initializer."""
            self._evaluate = model
            self._view = view
            # Connect signals and slots
            self._connectSignals()
     
        def _calculateResult(self):
            """Evaluate expressions."""
            result = self._evaluate(expression=self._view.displayText())
            self._view.setDisplayText(result)
     
        def _buildExpression(self, sub_exp):
            """Build expression."""
            if self._view.displayText() == ERROR_MSG:
                self._view.clearDisplay()
     
            expression = self._view.displayText() + sub_exp
            self._view.setDisplayText(expression)
     
        def _connectSignals(self):
            """Connect signals and slots."""
            for btnText, btn in self._view.buttons.items():
                if btnText not in {'=', 'C'}:
                    btn.clicked.connect(partial(self._buildExpression, btnText))
     
            self._view.buttons['='].clicked.connect(self._calculateResult)
            self._view.display.returnPressed.connect(self._calculateResult)
            self._view.buttons['C'].clicked.connect(self._view.clearDisplay)
    Chaque bouton est contenu dans un dictionnaire. Chaque clé du dictionnaire représente un bouton ('1','2','3',...'C' et '=')

    et enfin la fonction main:

    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
    # Client code
    def main():
        """Main function."""
        # Create an instance of `QApplication`
        pycalc = QApplication(sys.argv)
        # Show the calculator's GUI
        view = PyCalcUi()
        view.show()
        # Create instances of the model and the controller
        model = evaluateExpression
        PyCalcCtrl(model=model, view=view)
        # Execute calculator's main loop
        sys.exit(pycalc.exec_())
    if __name__ == '__main__':
        main()
    On voit bien ici que l'objet view est créé avec une référence "view". C'est une fenêtre simple avec quelques fonctions basiques dedans pour afficher l'expression désirée par l'utilisateur.
    de même, l'objet "model" est créé avec une référence "model".

    En revanche, l'objet controller n'a pas de référence, mais la connexion à ses fonctions marche correctement. C'est là que je n'arrive pas à faire le parallèle avec mon propre code.

  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,

    Citation Envoyé par francky380 Voir le message
    En revanche, l'objet controller n'a pas de référence, mais la connexion à ses fonctions marche correctement. C'est là que je n'arrive pas à faire le parallèle avec mon propre code.
    Çà fonctionne grâce à cette instruction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                btn.clicked.connect(partial(self._buildExpression, btnText))
    où "partial" fabrique une fonction qui à une référence à self, fonction qui sera "référencée" par la mécanique du "connect".

    Essayez ce code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from functools import partial
     
    class A:
        def do_print(self, msg):
            print(msg)
     
    a = A()
    z = partial(a.do_print, 'foo')
    z()
    del a
    z()
    Normalement, le deuxième z() devrait planter puisque a n'existe plus.

    Bon là c'est un peu violent mais imaginez un objet déréférencé dans votre code, son état n'a plus de sens. Pourtant "partial" le fait survivre et permet l'appel d' une de ses méthodes. Dans le meilleur des cas, çà plante... dans le pire, çà fait des choses inattendues et difficiles à diagnostiquer.

    Et si vous lisez attentivement la notice concernant "partial", elle n'est supposée être utilisée que pour des fonctions: le code de votre tuto. fonctionne "par chance" mais est incorrect.

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

  7. #7
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    13
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 13
    Points : 9
    Points
    9
    Par défaut
    Oh oui d'accord, je comprend mieux l'emploi de la fonction "partial". En me renseignant un peu dessus je n'avais pas très bien compris ce qu'elle faisait et encore moins cette aspect là de son utilisation.

    Finalement ce n'est pas une très bonne pratique qui est employée dans le tutoriel à ce que je vois.

    Merci pour ces éclairecissements.

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

Discussions similaires

  1. Problème d'intégration de boutons dans une Frame
    Par unic0 dans le forum Tkinter
    Réponses: 2
    Dernier message: 01/03/2015, 23h06
  2. Réponses: 6
    Dernier message: 13/11/2012, 08h17
  3. Problème d'affichage de boutons dans une Frame ayant une image en background
    Par felxio dans le forum Interfaces Graphiques en Java
    Réponses: 0
    Dernier message: 13/08/2012, 14h35
  4. Problème avec boutons dans une boucle
    Par CHAP26 dans le forum Flash
    Réponses: 2
    Dernier message: 03/06/2008, 14h28
  5. [CSS]problème centrage texte de bouton dans une boîte
    Par Aurelius dans le forum Mise en page CSS
    Réponses: 3
    Dernier message: 06/09/2005, 16h01

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