Python 如何在GUI线程上调用方法,但在QMainWindow类(Pyqt)中没有该方法
我只记录了崩溃(未处理的异常): 开始时,您只需从主线程调用CrashEngine.register(“sw”,“1.1.7”)Python 如何在GUI线程上调用方法,但在QMainWindow类(Pyqt)中没有该方法,python,multithreading,pyqt,pyqt5,Python,Multithreading,Pyqt,Pyqt5,我只记录了崩溃(未处理的异常): 开始时,您只需从主线程调用CrashEngine.register(“sw”,“1.1.7”) import sys import time import os import traceback from PyQt5.QtWidgets import * class CrashEngine: @staticmethod def register(name, version): CrashEngine.name = name
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)
在我遇到多线程应用程序之前,一切都运行得非常好,其中sys.excepthook有时是从不同于主线程的线程引发的。正如我们所知,从不同线程调用GUI将导致意外行为,并在大多数情况下崩溃
我只知道在QMainWindow中创建插槽,在CrashEngine中创建信号并连接它们。但这正是我不想看到的,因为CrashEngine在很多脚本、程序等中使用,我不想在所有脚本、程序中添加相同的代码(显示MsgBox)
更新:
我根据@three_Pinepples的建议重新编写了代码,但不是通过纯Python而是通过PyQt框架
@staticmethod
def __showDialog():
path = sys.executable
arg = os.path.dirname(os.path.abspath(__file__)) + "\\show_crash.py"
QProcess.startDetached(path, [arg])
sys.exit(1)
和show_crash.py包含:
import sys
import os
from PyQt5.QtWidgets import *
class ErrorWindow(QMessageBox):
def __init__(self):
super().__init__()
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")
self.setText(message)
self.setIcon(QMessageBox.Critical)
self.show()
def main():
app = QApplication(sys.argv)
ex = ErrorWindow()
sys.exit(app.exec_())
main()
可以按照您的建议(但希望避免)使用信号/插槽方法进行过帐,或者通过
QApplication.instance().postEvent()
将自定义事件过帐回Qt事件循环来处理此问题。这两种方法都存在根本性缺陷,因为它们依赖于Qt事件循环的正常运行(如果部分应用程序已进入错误状态,则情况可能并非如此)
在图形消息框中显示异常的唯一可靠方法是让异常处理程序启动一个创建消息框的新进程。编写一个显示sys.argv[1]的独立应用程序相当容易
,并使用excepthook处理程序中的subprocess.Popen
启动
我和我的同事已经为一个大型的Qt项目完成了这项工作,并且工作得非常好。我们还努力使用Tkinter启动消息框(几乎每一个Python安装都默认附带Tkinter)而不是Qt,以防异常是由Qt的安装丢失或损坏引起的。它是开源的。可以按照您的建议(但希望避免)使用信号/插槽方法进行发布,或者通过
QApplication.instance().postEvent()将自定义事件发回Qt事件循环来处理此问题
这两种方法都存在根本性的缺陷,因为它们依赖于Qt事件循环的正常运行(如果部分应用程序已进入错误状态,则可能不是这种情况)
在图形消息框中显示异常的唯一可靠方法是让异常处理程序启动一个创建消息框的新进程。编写一个显示sys.argv[1]的独立应用程序相当容易
,并使用excepthook处理程序中的subprocess.Popen
启动
我和我的同事已经为一个大型的Qt项目完成了这项工作,并且工作得非常好。我们还努力使用Tkinter启动消息框(几乎每一个Python安装都默认附带Tkinter)而不是Qt,以防异常是由Qt的安装丢失或损坏引起的。它是开源的。您真的没有选择:所有gui操作都必须在主线程中进行。但是,我不明白为什么您不能简单地公开
showDialog
函数,以便主窗口可以从连接到的插槽调用它a signal.PS:我还应该指出,您当前的代码中有一个非常糟糕的错误。一些异常会反复出现(例如递归错误)。这将导致数百个消息框相互重叠打开,除非您采取步骤检查其中一个是否已显示。@ekhumoro感谢您的回复,但您的第二条评论不正确。我使用无限递归进行了测试,得到了一个msgbox和崩溃日志,没有任何问题。有一个quit()在msgBox之后。你真的没有选择:所有gui操作都必须在主线程中进行。但是,我不明白为什么你不能简单地公开showDialog
函数,以便主窗口可以从连接到信号的插槽中调用它。PS:我还应该指出,你当前的代码中有一个非常严重的错误。一些异常重复重新引发(例如递归错误)。这将导致数百个消息框相互重叠打开,除非您采取步骤检查其中一个是否已显示。@ekhumoro感谢您的回复,但您的第二条评论不正确。我使用无限递归进行了测试,得到了一个msgbox和崩溃日志,没有任何问题。有一个quit()在msgBox.Perfect之后,我使用了你的建议并将其改写为Qt,因为我真的不喜欢Tkinter。但我在退出原始应用程序时遇到问题。请检查更新的答案。这样更新你的问题通常不是一个好主意,因为现在我的答案对阅读本文的任何人来说都没有意义。鼓励提出全新的问题如果您有后续问题,请提问。很好,我使用了您的建议并将其改写为Qt,因为我真的不喜欢Tkinter。但我在退出原始应用程序时遇到问题。请检查更新的答案。像这样更新您的问题通常不是一个好主意,因为现在我的答案对其他阅读本文的人来说没有意义。这是enc如果您有后续问题,我们会提出全新的问题。