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
• 14,960 points

1 answer to this question.

Your answer

Your name to display (optional):
Privacy: Your email address will only be used for sending these notifications.
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
• 56,100 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,500 points
+2 votes
11 answers

How to print array/ list without brackets in python?

name=["a","b","c"] print (', '.join(name)) It will simply take all ...READ MORE

answered Apr 18, 2018 in Python by aayushi
• 750 points
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
+3 votes
2 answers

how to print array integer without [] bracket in python like result = 1,2,3,4,5

Hey @abhijmr.143, you can print array integers ...READ MORE

answered Aug 4, 2018 in Python by Omkar
• 65,810 points

edited Aug 8, 2018 by Omkar 265 views
0 votes
1 answer

how can i count the items in a list?

suppose you have a list a = [0,1,2,3,4,5,6,7,8,9,10] now ...READ MORE

answered May 2 in Python by Mohammad
• 920 points
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
• 56,100 points

© 2018 Brain4ce Education Solutions Pvt. Ltd. All rights Reserved.
"PMP®","PMI®", "PMI-ACP®" and "PMBOK®" are registered marks of the Project Management Institute, Inc. MongoDB®, Mongo and the leaf logo are the registered trademarks of MongoDB, Inc.