如何在GUI线程上调用方法但在QMainWindow类中没有该方法(Pyqt)

时间:2018-03-20 13:49:23

标签: python multithreading pyqt pyqt5

我已经简单地记录了崩溃(未处理的异常): 在开始时,您可以从主线程中简单地调用CrashEngine.register(“sw”,“1.1.7”)。

$Categories =  CategoryOfItemsTrans::find()
        ->innerJoin('category_of_items','category_of_items_trans.CATEGORY_OF_ITEM_ID = category_of_items.CATEGORY_OF_ITEM_ID')
        ->where('category_of_items.CATEGORY_FLAG = \''.$CategoryFlag.'\' AND category_of_items_trans.LANGUAGE_ID ='.$LanguageID)
        ->all();

一切都运行良好,直到我遇到多线程应用程序,其中sys.excepthook有时从主线程以外的不同线程引发。我们知道从不同线程调用GUI会导致意外行为并在大多数时间内崩溃。

我唯一知道的是在QMainWindow中创建插槽并在CrashEngine中创建Signal并连接它们。但这是我不想要的,因为CrashEngine被用在如此多的脚本,程序等中,而且我不想在所有这些代码中添加相同的代码片段(显示MsgBox)。

更新 我根据@three_pineapples建议重新编写代码,但是通过PyQt框架而不是纯Python。

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

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

    @staticmethod
    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: " + CrashEngine.name + "\n")
            f.write("Software version: " + CrashEngine.version + "\n")
            f.write("\n")
            f.write(crash)

        CrashEngine.__showDialog()

    @staticmethod
    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)
        msg.exec()
        quit(1)

和show_crash.py包含:

@staticmethod
def __showDialog():
    path = sys.executable
    arg = os.path.dirname(os.path.abspath(__file__)) + "\\show_crash.py"
    QProcess.startDetached(path, [arg])
    sys.exit(1)

1 个答案:

答案 0 :(得分:1)

可以通过使用您建议的信号/插槽方法发布(但希望避免)或通过QApplication.instance().postEvent()将自定义事件发布回Qt事件循环来处理此问题,这两种方法都是从根本上是有缺陷的,因为它们依赖于Qt事件循环正常运行(如果您的应用程序的一部分已进入错误状态,情况可能并非如此)。

在图形消息框中显示异常的唯一可靠方法是让异常处理程序启动创建消息框的新进程。编写一个在消息框中显示sys.argv[1]的独立应用程序,并使用来自excepthook处理程序的subprocess.Popen启动该应用程序,相当容易。

我和我的同事为一个大型Qt项目做了这个,它运作得很好。我们还使用Tkinter(默认情况下几乎每次安装Python)而不是Qt启动消息框,以防异常是由Qt的安装丢失或损坏引起的。它是开源的here