捕捉 QApplication 引发的异常。

13

我正在尝试使用PyQt5编写一个可以在系统托盘中工作的应用程序。 代码有时会引发异常,因此我需要能够捕捉它们。

我期望当应用程序发生异常时,主事件循环会退出,因此像这样捕获它应该可以:

try:
    application.exec()
except:
    do_stuff()
在下面的示例中,当我按下“Raise”按钮时,我只看到了回溯信息,但从未看到打印出error catched!

在下面的示例中,当我按下“Raise”按钮时,我只看到了回溯信息,但从未看到打印出error catched!

from PyQt5 import QtWidgets, QtGui, QtCore

class ErrorApp():
    def __init__(self):
        # Init QApplication, QWidet and QMenu
        self.app = QtWidgets.QApplication([])
        self.widget = QtWidgets.QWidget()
        self.menu = QtWidgets.QMenu("menu", self.widget)

        # Add items to menu
        self.menu_action_raise = self.menu.addAction("Raise")
        self.menu_action_raise.triggered.connect(self.raise_error)

        self.menu_action_exit = self.menu.addAction("Exit")
        self.menu_action_exit.triggered.connect(self.app.exit)

        # Create the tray app
        self.tray = QtWidgets.QSystemTrayIcon(QtGui.QIcon("logo.png"), self.widget)
        self.tray.setContextMenu(self.menu)

        # Show app
        self.tray.show()

    def raise_error(self):
        assert False

e = ErrorApp()

try:
    e.app.exec()

except:
    print("error catched!")
有2个类似的问题,但那里的答案不能满足我的需求:在PyQt中捕获任何异常:OP想要监视异常,事件循环没有退出。防止PyQt静默处理在插槽中发生的异常:修饰符答案根本不起作用;将sys.exit(1)添加到sys.excepthook中只会关闭整个程序,而不会打印error catched!
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
28

您必须使用异常,并且如果要结束事件循环,则必须调用quit()(或exit())方法。

import sys
import traceback
from PyQt5 import QtWidgets, QtGui, QtCore


class ErrorApp:
    # ...

    def raise_error(self):
        assert False


def excepthook(exc_type, exc_value, exc_tb):
    tb = "".join(traceback.format_exception(exc_type, exc_value, exc_tb))
    print("error catched!:")
    print("error message:\n", tb)
    QtWidgets.QApplication.quit()
    # or QtWidgets.QApplication.exit(0)


sys.excepthook = excepthook
e = ErrorApp()
ret = e.app.exec_()
print("event loop exited")
sys.exit(ret)

输出:

error catched!:
error message:
 Traceback (most recent call last):
  File "main.py", line 28, in raise_error
    assert False
AssertionError

event loop exited

哦,我明白了 - 我必须在excepthook中处理它,而不是我的尝试。谢谢 :) - Mikołaj Kuranowski
在 excepthook 函数的末尾是否应该调用正常的 sys.__excepthook__(exc_type, exc_value, exc_tb) 函数? - ymmx
exitQCoreApplication 的静态方法,而 quitQCoreApplication 的“静态槽”(不确定两者有什么区别)。在 QApplication 的“所有成员列表(包括继承的)”中,它包括 exit(显然链接到 QCoreApplication 的文档页面),但不包括 quit。然而,根据您的代码,两者似乎都可以工作。我们是否只是假设这些“静态”方法/槽会“落入”适当的超类? - mike rodent
2
@mikerodent quit() 函数出现在 QApplication 成员列表中,它在 primaryScreenChanged 后的第一列中,看起来顺序是先放属性、信号和槽,然后才是其他方法。注意:槽是在 QMetaObject 中注册的函数。 - eyllanesc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,