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 :

core dumped depuis des QPushButton


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut core dumped depuis des QPushButton
    Bonsoir,

    je rencontre un soucis depuis un bon moment, en effet très souvent, lorsque je ferme mon logiciel via un QPushButton qui lance un self.close, j'ai le droit à un Erreur de segmentation (core dumped).

    j'ai vu qu'en utilisant setAttribute(Qt.WA_DeleteOnClose) ça réglait le souci... enfin presque...

    je rencontre encore le soucis si j'utilise des QMessageBox ou autre fenêtre comme QInputDialog qui sont suivis d'un self.close().

    j'ai essayé de reproduire le problème en repartant à 0 mais je ne suis pas arrivé à grand chose...

    Mais ce qui m'interpelle le plus, c'est que j'arrive à contourner le problème en donnant le focus au bouton (via un clic droit ou en le définissant comme bouton par défaut).

    En faisant ainsi, je n'ai JAMAIS de core dumped...

    Du coup je ne pige pas du tout le problème...

    J'ai essayé de reproduire le bug avec :
    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
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    import sys
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
     
    class Fenetre(QWidget):
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
     
            Window = QMessageBox(3, QCoreApplication.translate("main", "Tesseract langs error"), QCoreApplication.translate("main", "The subtitle language is not avaible in Tesseract list langs:\n{}"), QMessageBox.Close, self, Qt.WindowSystemMenuHint)
            Button = QPushButton(QIcon.fromTheme("preferences-desktop-locale", QIcon(":/img/preferences-desktop-locale.png")), QCoreApplication.translate("main", "Use another language"), Window)
            Window.addButton(Button, QMessageBox.YesRole) # Ajout du bouton
            Window.setDefaultButton(Button) # Bouton par défaut
            Window.exec() # Message d'information
     
            # Arret de la fonction
            self.close()
     
     
        def closeEvent(self, event):
            exit(0)
     
     
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        fen = Fenetre()
        fen.setAttribute(Qt.WA_DeleteOnClose)
        sys.exit(app.exec_())
    mais je préfère joindre mon vrai fichier.

    Le code de la fenêtre sera ligne 115, j'ai virer les différents tests pour ne pas que ça vous bloque.
    Il suffit d'annuler l'une des 2 fenêtres qui se suivent.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ./TesseractQt.py -l "caca" FichierBidon FichierBidon
    Pour info ça me le fait sur différents logiciels, donc je suis surement passé à coté de quelque chose.
    Et jamais de problème via la croix de la fenêtre ou via un menu et un triggered.

    J’espère avoir été clair... merci à vous d'avance !
    Fichiers attachés Fichiers attachés

  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 Hizoka,

    Le message "Erreur de segmentation (core dumped)" après fermeture est assez courant, il s'explique par le fait que la destruction d'objets Qt côté C++ et la suppression de leur référence par le garbage collector de Python sont deux choses qui s'exécutent dans un ordre non prédictible.

    Exemple, lorsque tu cliques sur le bouton, closeEvent est appelé parce que tu l'y as connecté mais aussi des choses comme paintEvent et plein d'autres trucs insoupçonnés.

    En forçant Qt à terminer son travail avant de supprimer-fermer-détruire quoique ce soit le message ne devrait plus apparaître.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        def closeEvent(self, e):
            QtCore.QCoreApplication.processEvents()
            sys.exit() # ou dialog.accept() ou autre ...

  3. #3
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    A priori, je ne vois aucune raison d'utiliser le "exit()" dans le closeEvent, et il est possible que ce soit lui qui pose problème.

    Voilà comment je fais:

    - j'ai en général un bouton "Quitter" qui lance une méthode "quitter", et qui représente la manière normale de fermer la fenêtre (et donc le programme si c'est la fenêtre principale). Cette méthode fait ce qui doit être fait, par exemple enregistrer des données, etc... et se termine par un "self.close()" qui suffit à lui seul pour fermer la fenêtre.

    - la méthode closeEvent, n'est pas indispensable, mais elle peut être utile si on veut faire quelque chose de plus quand l'utilisateur ferme la fenêtre en cliquant sur sa croix de fermeture ou par son menu système, et donc sans passer par le "self.close()". Par exemple, on peut arrêter de force un processus QProcess encore en cours d'exécution. Comme closeEvent est une méthode de QWidget, il s'agit d'une surcharge. Et le self.close() de la méthode quitter, lance lui-aussi closeEvent.

    Grâce à la surcharge de cette méthode, on peut accepter (event.accept()) ou refuser (event.ignore()) la fermeture. L'acceptation est par défaut.

    Lors d'une acceptation de cette fermeture, la fenêtre disparait de l'affichage. Si en plus on a lancé la fenêtre avec setAttribute(QtCore.Qt.WA_DeleteOnClose), cette fenêtre est détruite. Et la boucle principale de traitement des évènements qui est le "app.exec_()" se termine alors en passant sa valeur de fin à sys.exit().

    Voilà un petit code de test qui fait ça. Pour montrer cette mécanique, j'ai mis une question finale du genre "vous êtes sûr?".

    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
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    # Python 3
     
    import sys
    from PyQt5 import (QtWidgets, QtCore)
     
    #############################################################################
    class Fenetre(QtWidgets.QWidget):
     
        def __init__(self, parent=None):
            super().__init__(parent)
            self.resize(200, 100)
     
            self.boutonquitter = QtWidgets.QPushButton("Quitter", self)
            self.boutonquitter.clicked.connect(self.quitter)
     
            posit = QtWidgets.QGridLayout()
            posit.addWidget(self.boutonquitter, 0, 0)
            self.setLayout(posit)
     
        @QtCore.pyqtSlot()
        def quitter(self):
            """fermeture normale de la fenêtre
            """
            # sauvegarder ce qui doit l'être
            # ...
            # et fermer la fenêtre 
            self.close()
     
        def closeEvent(self, event):
            """appelé lors de la fermeture de la fenêtre
               quelque soit la méthode utilisée
            """
            reponse = QtWidgets.QMessageBox.question(self,
                        "Demande d'arrêt", 
                        "Vous êtes sûr de vouloir arrêter le programme?", 
                        buttons = QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, 
                        defaultButton = QtWidgets.QMessageBox.NoButton)
     
            if reponse == QtWidgets.QMessageBox.Yes:
                event.accept() # accepte la fermeture
            else:
                event.ignore() # refuse la fermeture
     
    #############################################################################
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        fen = Fenetre()
        fen.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        fen.show()
        sys.exit(app.exec_())

  4. #4
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut
    Vins => QCoreApplication.processEvents() ne change rien chez moi, j'en ai mis à plusieurs endroits histoire d'être sûr mais idem.
    merci pour l'explications déjà
    mais j'ai du mal à piger qu'il y est une si grande différence dans les traitements si je prends le focus sur le bouton avant (même en laissant appuyer dessus 1s) je n'ai plus aucun problème...
    y a moyen de savoir le travail qu'il lui reste à faire justement ?


    tyrtamos => C'est comme ça que je fais déjà sur mes gros logiciels.
    et j'ai testé justement sans la fonction close mais avec une fonction simple, c'est pareil

    dans le cas présent, c'est un code plus que bancal et il a besoin de l'exit :p


    J'ai testé donc en passant par d'autres fonctions, en lui demandant d'attendre, en ne mettant pas de bouton maison dedans...

    pour le moment la seule façon que j'ai trouvé pour détourner le problème, c'est de définir le bouton close par défaut... mais j'aime pas trop le principe pour le coup...
    et c'est pas top, car si on change de focus avant de cliquer dessus, pouf ! ça recommence


    Merci pour vos aides, si vous avez une autre idée, je suis preneur

    Bon dimanche à vous.

    arf la doc qt n'est plus accessible en plus...
    http://doc.qt.io/qt-5/classes.html




    EDIT : y a un truc que je pige pas...
    dans mon petit soft, si je lance la fonction Fermeture qui affiche des print et fait un self.close() (sans fonction closeEvent), le logiciel n'est pas fermé...

  5. #5
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut
    Je relance le sujet au cas où...

    j'ai fait d'autres tests comme mettre l'affichage de la fenêtre dans un QThread en me disant que ça laisserait peut être plus de temps mais nope... pas de changement...

  6. #6
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Citation Envoyé par hizoka Voir le message
    j'ai fait d'autres tests comme mettre l'affichage de la fenêtre dans un QThread en me disant que ça laisserait peut être plus de temps mais nope... pas de changement...
    Je continue à penser que tu as tort de terminer ton programme avec "sys.exit()" à cet endroit: il n'est pas seulement inutile, il est nuisible.

    Au début du programme, tu demandes à Python de lancer la bibliothèque graphique avec "app = QtWidgets.QApplication(sys.argv)". Cette bibliothèque se met en place avec une certaine logique, et il faut respecter celle-ci jusqu'à son arrêt. Dans ce cadre, le fait de faire un "sys.exit()" en plein milieu du code graphique est d'une grande sauvagerie...

    En tout cas, je n'en ai jamais eu besoin: self.close() est suffisant pour arrêter une fenêtre, et si c'est la fenêtre principale, c'est la boucle de traitement des évènements "app.exec_()" qui se terminera proprement en passant son code au dernier sys.exit().

    Surcharger closeEvent n'est utile que si on veut faire quelque chose de particulier quand l'utilisateur clique sur la croix pour arrêter la fenêtre (exemples: la question "Vous êtes sûr? ou l'arrêt d'un processus en cours, etc...). Mais à ce stade, la machinerie d'arrêt de la fenêtre est déjà en place, et il n'est pas normal d'avoir besoin de sys.exit() en plus!

    Cependant, il m'est déjà arrivé d'avoir des warnings à l'arrêt du programme, parce que j'utilisais des modules de gestion de base de données, et que "je ne faisais pas le ménage" correctement à la fin: il existait alors des ressources que mon code n'avait pas libérées à l'arrêt du programme. J'ai travaillé cette question, et les warnings ont cessé.

    A mon avis, c'est dans cette direction qu'il faut chercher: tu as quelque chose d'anormal dans ton code qui t'empêche d'arrêter ton programme correctement!.

    Je ne sais pas si ça peut t'aider, mais pendant la mise au point de mes programmes, il y a quelque chose dont j'ai horreur: c'est quand un programme s'arrête brutalement pendant son fonctionnement sans rien dire! Pour qu'il y ait tout de même un message avec un motif d'arrêt en cas d'erreur fatale, j'utilise une fonctionnalité de PyQt5: "QtCore.qInstallMessageHandler(messagederreur)". Et la fonction "messagederreur" contient en gros ça:

    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
    def messagederreur(msgtyp, context, msg):
     
        if msgtyp==QtCore.QtDebugMsg:
            print("Debug PyQt5: %s\n" % (msg,))
     
        elif msgtyp==QtCore.QtWarningMsg:
            print("Warning PyQt5: %s\n" % (msg,))
     
        elif msgtyp==QtCore.QtCriticalMsg or msgtyp==QtCore.QtFatalMsg or msgtyp==QtCore.QtSystemMsg:
            print("Critical/fatal/système PyQt5: %s\n" % (msg,))
            QtWidgets.QMessageBox.critical(None, 
                "Erreur critique PyQt5",
                "Critical/fatal/system: {}\n".format(msg) +\
                "Fichier: {}\n".format(context.file) +\
                "Ligne: {}\n".format(context.line) +\
                "Fonction: {}\n".format(context.function)
                )
        else:
            # message retourné par QtCore.QtInfoMsg créé à partir de Qt 5.5
            print("Info PyQt5: %s\n" % (msg,))
    A noter qu'avec ça, on peut en plus désactiver l'affichage de certains warnings lorsqu'ils sont provoqués par un bug de Qt.

  7. #7
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Novembre 2013
    Messages
    563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2013
    Messages : 563
    Par défaut
    Le truc, c'est que self.close ne fonctionne pas dans le cas présent... il continue quand même à exécuter le code qui suit...

    y a un truc qui doit bloquer, mais même en virant tout au max, je trouve pas...
    même avec event.accept() ça change rien.


    Mais vraiment le truc que je pige pas c'est pourquoi qu'en fonction du bouton de la fenêtre qui avait le focus, ca plante ou non...
    Je ne fais que récupérer la valeur de sortie de la fenêtre via les boutons...


    Pour les sys.exit(), c'était vraiment pour tester si ça changeait quelque chose mais pas de changement.


    Je suis désolé de te demander ça, mais peux tu jeter un oeil au code que j'ai épuré au max, s'il te plait et me dire si tu as le problème, s'il te plait ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ./Qtesseract.py -l fraaaa fichierbidon fichierbidon

    Il ne me reste que cette dépendance à terminer pour que mon logiciel soit complet et fonctionnel sans erreur... et je tourne en rond...


    merci pour les infos des messages d'erreurs, je vais regarder ça pour l'ajouter à mon soft.


    Merci beaucoup pour le temps que vous m'accordez tous !
    Fichiers attachés Fichiers attachés

Discussions similaires

  1. Générer des core dump sur serveur linux
    Par Joyus dans le forum Linux
    Réponses: 1
    Dernier message: 14/10/2007, 12h19
  2. soluce pour probleme non resolu depuis des mois
    Par jadey dans le forum Flash
    Réponses: 5
    Dernier message: 02/07/2006, 18h26
  3. Alimenter 1 BD depuis des sources hétérogènes
    Par Boogabi dans le forum Alimentation
    Réponses: 3
    Dernier message: 26/04/2006, 14h11
  4. Problème de Core Dumped !
    Par KneXtasY dans le forum C
    Réponses: 8
    Dernier message: 24/12/2005, 13h11
  5. Segmentation fault (core dumped)
    Par Battosaiii dans le forum C
    Réponses: 13
    Dernier message: 25/11/2005, 18h36

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