How to invoke method on GUI thread but without have that method in QMainWindow class (Pyqt)

0 votes

I have made the simply logging of crashes (unhandled exceptions): At start you simple call CrashEngine.register("sw", "1.1.7") from main thread.

import sys
import time
import os
import traceback
from PyQt5.QtWidgets import *

class CrashEngine:
    def register(name, version): = name
        CrashEngine.version = version
        sys.excepthook = CrashEngine.__logCrash

    def __logCrash(exc_type, exc_value, exc_traceback):
        crash = "".join(traceback.format_exception(exc_type, exc_value, exc_traceback))
        with open("crash.log", "w") as f:
            f.write(time.ctime() + "\n")
            f.write("Software name: " + + "\n")
            f.write("Software version: " + CrashEngine.version + "\n")


    def __showDialog():
        message = ("Fatal error occurred and application will be terminated.\n\n"
                   "Crash log was created at:\n" +
                    os.getcwd() + "\crash.log.\n\n"
                   "Please send log to ***@***.com")
        msg = QMessageBox(QMessageBox.Critical, "Application Crashed", message)

Everything worked excellent until i have meet multithreaded app where is sys.excepthook raised sometimes from different thread than main thread. As we know Calling GUI from different threads will result in unexpected behavior and crash in most of time.

The only thing i know is create slot in QMainWindow and create Signal in CrashEngine and connect them. But this is what I don't want to because CrashEngine is used in so many scripts, programs, etc and I don't want to add same piece of code (showing MsgBox) in all of them.

UPDATE: I reworked code according to @three_pineapples suggestion but via PyQt framework instead of pure Python.

def __showDialog():
    path = sys.executable
    arg = os.path.dirname(os.path.abspath(__file__)) + "\\"
    QProcess.startDetached(path, [arg])

and contains:

import sys
import os
from PyQt5.QtWidgets import *

class ErrorWindow(QMessageBox):
    def __init__(self):

        self.setWindowTitle("Application Crashed")
        message = ("Fatal error occurred and application was terminated.\n\n"
                   "Crash log was created at:\n" +
                   os.getcwd() + "\crash.log.\n\n"
                   "Please send log to ***@***.com")

def main():
    app = QApplication(sys.argv)
    ex = ErrorWindow()


Sep 24, 2018 in Python by bug_seeker
• 15,400 points

1 answer to this question.

0 votes

It is possible to handle this by posting using the signal/slot approach as you suggest (but would like to avoid) or by posting a custom event back to the Qt event loop via QApplication.instance().postEvent() both of these methods are fundamentally flawed because they rely on the Qt event loop functioning correctly (which may not be the case if part of your application has entered an error state).

The only reliable way to show an exception in a graphical message box is to have your exception handler launch a new process that creates the message box. It's reasonably easy to write a standalone application that shows sys.argv[1] in the message box, and to launch that using subprocess.Popen from your excepthook handler.

My colleagues and I have done this for a large Qt project, and it works very well. We've also gone to the effort of launching the message box using Tkinter (which ships by default with almost every Python install) rather than Qt, just in case the exception is caused by a missing or broken installation of Qt. It's open-sourced here.

answered Sep 24, 2018 by Priyaj
• 57,550 points

Related Questions In Python

0 votes
1 answer

Question on PyQt: How to connect a signal to a slot to start a background operation in Python

It shouldn't matter whether the connection is ...READ MORE

answered Nov 27, 2018 in Python by Nymeria
• 3,520 points
+2 votes
11 answers
0 votes
1 answer

Raw_input method is not working in python3. How to use it?

raw_input is not supported anymore in python3. ...READ MORE

answered May 4, 2018 in Python by aayushi
• 750 points
+1 vote
2 answers

how can i count the items in a list?

Syntax :            list. count(value) Code: colors = ['red', 'green', ...READ MORE

answered Jul 6, 2019 in Python by Neha
• 330 points

edited Jul 8, 2019 by Kalgi 1,184 views
0 votes
0 answers
0 votes
1 answer
0 votes
1 answer

“stub” __objclass__ in a Python class how to implement it?

You want to avoid interfering with this ...READ MORE

answered Sep 27, 2018 in Python by Priyaj
• 57,550 points