【问题标题】:How to capture output of Python's interpreter and show in a Text widget?如何捕获 Python 解释器的输出并在 Text 小部件中显示?
【发布时间】:2012-01-11 11:35:21
【问题描述】:

我有一个带有 PyQt 的 Python 程序,旨在在 Windows 上运行。 该程序进行大量操作并打印大量信息。 但是因为我想冻结它并且不希望出现提示屏幕,所以我希望所有这些信息都出现在主应用程序中,在 QTextEdit 左右。 我怎样才能使程序工作,以便它从解释器获取输出并同时在 textEdit 上显示它,就像它在真正的解释器上一样?

【问题讨论】:

    标签: python python-3.x pyqt


    【解决方案1】:

    不幸的是,该示例不适用于 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)
    

    【讨论】:

    • 根据new sintax,应该是sys.stdout.textWritten.connect(self.write2Console)
    【解决方案2】:

    我不久前在Terminal like app in PySide 上发布了一些有关 PySide 终端应用程序的内容。如果您正在查看 PyQt,那么还要检查 PySide。除了许可和语法上的一些差异之外,它们基本上是相同的。

    【讨论】:

      【解决方案3】:

      我假设“解释器的输出”是指写入控制台或终端窗口的输出,例如使用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))
      

      现在,在您的 GUI 中,将此流的一个实例安装到 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()
      

      【讨论】:

      • 我喜欢你的建议。看起来真的很容易实现。但是我需要为它创建一个新的类吗?我的意思是,我可以在主窗口的同一个类中创建写函数吗?
      • @dex19dt:当然可以,但我建议不要这样做,因为它违反了单一责任原则。在我的代码中,我创建了一个流类,它是QObject 的子类,并具有由write() 发出的textWritten 信号。然后,我只需将此信号与窗口中的一个插槽连接,该插槽将文本附加到QTextEdit。优点:可以对正常输出和错误输出进行不同的格式化;后者使用红色文本颜色。
      • 好的。所以我创建了另一个名为 stream.py 的文件并粘贴了您编写的代码。我将它导入到主程序中,它没有引发任何错误,但它也没有在 textEdit 小部件中插入文本。我的write函数简直就是self.textEdit.append(str(text))是不是错了?
      • @dex19dt:您似乎在某个地方有错误。我建议你暂时离开sys.stderr,然后尝试捕获sys.stdout。这样,您的流代码中的任何异常都会照常显示。事实上,如果您的write() 函数引发异常,您可能会陷入无限循环!
      • 我创建了另一个名为 stream.py 的文件并将您的代码粘贴到那里。我将它导入到主程序中,但它不会在 textEdit 小部件上显示文本。我的写函数是self.textEdit.append(str(text)),我知道这是不对的。我怎样才能到达另一个文件的另一个类中的 textEdit?附言是的,我删除了 stderr 部分,谢谢。
      【解决方案4】:

      我建议你使用日志库。 http://docs.python.org/library/logging.html 您可以编写自己的日志处理程序来与 QTextEdit 进行通信。这是一个很好的教程,可以帮助您入门:http://pantburk.info/?blog=77

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-06
        • 2011-04-16
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多