在pyqt QMessageBox中显示stderr



我想从PyQt脚本中捕获stderr输出,并将其显示在QMessageBox中。我找到了这些帖子并尝试了一下,但没有一个真正对我有用:

在QMessageBox 中显示python控制台消息

从辅助线程将stdout和stderr重定向到PyQt4 QTextEdit

PYQT:如何捕获python的输出';s解释器并将其显示在QEditText中?

我遇到了几个问题。首先,一个错误似乎是作为一系列单独的stderr消息发送的(至少在Python 3.4中是这样)。这导致使用我找到的方法打开多个消息框,并且需要使用.show()而不是.exec(),并将单独的消息累积为一个。

此外,如果出现第二个错误,即使第一个消息框已关闭,第一个错误的文本仍会保留在新消息框中。我试着调用.destroy()并使用Qt.WA_DeleteOnClose,但第一个消息框实际上并没有消失。因此,我最终只是简单地删除了持久消息框中的文本。

找到一种干净的方法来同时显示"关闭窗口"one_answers"OK"事件也需要一些实验。

我做了一些似乎能完成任务的东西,而且尽我所能简单。如果有人有改进或能解释我在这里遇到的问题,请编辑代码。

这是一个示例,它用一个按钮启动一个简单的主窗口来创建stderr。错误消息被捕获并显示在消息框中,该消息框在"OK"或关闭时正确清除。该技术也可以与stdout一起使用。

from PyQt4 import QtGui
class StdErrHandler():
    def __init__(self):
        # To instantiate only one message box
        self.err_box = None
    def write(self, std_msg):
        # All that stderr or stdout require is a class with a 'write' method.
        if self.err_box is None:
            self.err_box = QtGui.QMessageBox()
            # Both OK and window delete fire the 'finished' signal
            self.err_box.finished.connect(self.clear)
        # A single error is sent as a string of separate stderr .write() messages, 
        # so concatenate them.
        self.err_box.setText(self.err_box.text() + std_msg)
        # .show() is used here because .exec() or .exec_() create multiple
        # MessageBoxes.
        self.err_box.show()
    def clear(self):
        # QMessageBox doesn't seem to be actually destroyed when closed, just hidden.
        # This is true even if destroy() is called or if the Qt.WA_DeleteOnClose 
        # attribute is set.  Clear text for next time.
        self.err_box.setText('')
class AppMainWindow(QtGui.QMainWindow):
    """
    Main window with button to create an error
    """
    def __init__(self, parent=None):
        # initialization of the superclass
        super(AppMainWindow, self).__init__(parent)
        self.create_err = QtGui.QPushButton(self)
        self.create_err.setText("Create Error")
        self.create_err.clicked.connect(self.err_btn_clicked)
    def err_btn_clicked(self):
        # Deliberately create a stderr output
        oopsie
if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    amw = AppMainWindow()
    amw.show()
    # Instantiate stderr handler class
    std_err_handler = StdErrHandler()
    # Connect stderr to the handler
    sys.stderr = std_err_handler
    sys.exit(app.exec_())

编辑:正如three_pineapples指出的那样,这不是线程安全的。我发现,当我在另一个应用程序中安装此程序时,如果在pydev调试器下运行应用程序时发生stderr,则消息框将挂起,这可能是由于此原因。

我使用线程和队列重写了它,但这也挂起了。

然后我了解到PyQt信号&插槽是线程安全的,所以我只使用它重写它。下面的版本是线程安全的(我认为),可以作为独立脚本或在调试器下正确运行:

from PyQt4 import QtCore, QtGui
class StdErrHandler(QtCore.QObject):
    '''
    This class provides an alternate write() method for stderr messages.
    Messages are sent by pyqtSignal to the pyqtSlot in the main window.
    '''
    err_msg = QtCore.pyqtSignal(str)
    def __init__(self, parent=None):
        QtCore.QObject.__init__(self)
    def write(self, msg):
        # stderr messages are sent to this method.
        self.err_msg.emit(msg)
class AppMainWindow(QtGui.QMainWindow):
    '''
    Main window with button to create an error
    '''
    def __init__(self, parent=None):
        # initialization of the superclass
        super(AppMainWindow, self).__init__(parent)
        # To avoid creating multiple error boxes
        self.err_box = None
        # Single button, connect to button handler
        self.create_err = QtGui.QPushButton(self)
        self.create_err.setText("Create Error")
        self.create_err.clicked.connect(self.err_btn_clicked)
    def err_btn_clicked(self):
        # Deliberately create a stderr output
        oopsie
    def std_err_post(self, msg):
        '''
        This method receives stderr text strings as a pyqtSlot.
        '''
        if self.err_box is None:
            self.err_box = QtGui.QMessageBox()
            # Both OK and window delete fire the 'finished' signal
            self.err_box.finished.connect(self.clear)
        # A single error is sent as a string of separate stderr .write() messages,
        # so concatenate them.
        self.err_box.setText(self.err_box.text() + msg)
        # .show() is used here because .exec() or .exec_() create multiple
        # MessageBoxes.
        self.err_box.show()
    def clear(self):
        # QMessageBox doesn't seem to be actually destroyed when closed, just hidden.
        # This is true even if destroy() is called or if the Qt.WA_DeleteOnClose
        # attribute is set.  Clear text for next time.
        self.err_box.setText('')
if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    amw = AppMainWindow()
    amw.show()
    # Create the stderr handler and point stderr to it
    std_err_handler = StdErrHandler()
    sys.stderr = std_err_handler
    # Connect err_msg signal to message box method in main window
    std_err_handler.err_msg.connect(amw.std_err_post)
    sys.exit(app.exec_())

相关内容

  • 没有找到相关文章

最新更新