如何捕获Python解释器的输出并在Text控件中显示?

24 投票
5 回答
34837 浏览
提问于 2025-04-17 07:32

我有一个用Python和PyQt写的程序,专门在Windows上运行。这个程序会进行很多操作,并且打印出很多信息。不过因为我想把它打包成一个独立的应用,不想让命令提示符窗口出现,所以我希望所有的信息都能在主应用程序里显示,比如在一个QTextEdit控件里。请问我该怎么做,才能让程序在运行时把解释器的输出同时显示在textEdit里,就像在真实的解释器里那样?

5 个回答

2

我建议你使用日志库。你可以在这里找到相关文档:http://docs.python.org/library/logging.html。你还可以为QTextEdit写一个自己的日志处理器。这里有一个很好的教程,可以帮助你入门:http://pantburk.info/?blog=77

7

很遗憾,这个例子在使用PySide时不太管用。它会出现以下错误:

sys.stdout = EmittingStream(textWritten=self.write2Console)
AttributeError: 'textWritten()' is not a Qt property or a signal

为了让它能在PySide上正常运行,我们需要做以下修改:

sys.stdout = EmittingStream()
self.connect(sys.stdout,QtCore.SIGNAL('textWritten(QString)'),self.write2Console)
41

我想你提到的“解释器的输出”是指在控制台或终端窗口中显示的内容,比如用 print() 打印出来的东西。

Python 所有的控制台输出都会写入程序的输出流 sys.stdout(正常输出)和 sys.stderr(错误输出,比如异常的追踪信息)。这些输出流就像文件一样。

你可以用自己的文件样的对象来替换这些输出流。你只需要提供一个 write(text) 函数就可以了。通过提供你自己的实现,你可以把所有的输出转发到你的小部件上:

class MyStream(object):
    def write(self, text):
        # Add text to a QTextEdit...

sys.stdout = MyStream()
sys.stderr = MyStream()

如果你需要重置这些输出流,它们仍然可以通过 sys.__stdout__sys.__stderr__ 来访问:

sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__

更新

这里有一些适用于 PyQt4 的示例代码。首先定义一个流,它会通过 Qt 信号报告写入的数据:

from PyQt4 import QtCore

class EmittingStream(QtCore.QObject):

    textWritten = QtCore.pyqtSignal(str)

    def write(self, text):
        self.textWritten.emit(str(text))

然后,在你的图形界面中,将这个流的实例安装到 sys.stdout,并将 textWritten 信号连接到一个槽,这个槽会把文本写入到 QTextEdit 中:

# Within your main window class...

def __init__(self, parent=None, **kwargs):
    # ...

    # Install the custom output stream
    sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)

def __del__(self):
    # Restore sys.stdout
    sys.stdout = sys.__stdout__

def normalOutputWritten(self, text):
    """Append text to the QTextEdit."""
    # Maybe QTextEdit.append() works as well, but this is how I do it:
    cursor = self.textEdit.textCursor()
    cursor.movePosition(QtGui.QTextCursor.End)
    cursor.insertText(text)
    self.textEdit.setTextCursor(cursor)
    self.textEdit.ensureCursorVisible()

撰写回答