PySide:将stdout重定向到对话框

时间:2015-01-09 09:46:54

标签: python python-2.7 pyqt stdout pyside

我有一个pyside应用程序,它在QThread中运行一个函数。此功能通常使用print。如何将stdout重定向到对话框(包含qtextedit或类似对话框),该对话框将在函数运行时显示。

这是一个最小的例子:

class Main(QtGui.QWindow):
  def __init__(self):
      super(Main, self).__init__()
      self.run_button = QtGui.QPushButton("Run")

      mainLayout = QtGui.QVBoxLayout()
      mainLayout.addWidget(self.run_button)
      self.setLayout(mainLayout)

      self.run_button.clicked.connect(self.run_event)


  def run_event(self):
      # Create the dialog to display output
      self.viewer = OutputDialog()

      # Create the worker and put it in a thread
      self.worker = Worker()
      self.thread = QtCore.QThread()
      self.worker.moveToThread(self.thread)
      self.thread.started.connect(self.worker.run)
      self.worker.finished.connect(self.thread.quit)

      self.thread.start()


class Worker(QtCore.QObject):
  finished = QtCore.Signal()

  def run(self):
    for i in range(10):
      print "Im doing stuff" 
      time.sleep(1)
    self.finished.emit()


class OutputDialog(QtGui.QDialog):
  def __init__(self, parent=None):

    super(OutputDialog, self).__init__(parent)
    self.text_edit = QtGui.QTextEdit()
    mainLayout = QtGui.QVBoxLayout()
    mainLayout.addWidget(self.text_edit)

    self.setLayout(vbox)

我可以修改worker以将stdout重定向到自身,然后将文本作为信号发出:

class Worker(QtCore.QObject):
  finished = QtCore.Signal()
  message = QtCore.Signal(str)

 def __init__(self):
   super(Worker, self).__init__()

   sys.stdout = self

 def run(self):
    for i in range(10):
      print "Im doing stuff" 
      time.sleep(1)
    self.finished.emit()


 def write(self, text):
     self.message.emit(text)

但是当我将此信号连接到OutputDialog实例时,只有在工作人员完成后才显示文本。

我也试过在这里实现这个方法: Redirecting stdout and stderr to a PyQt4 QTextEdit from a secondary thread

但它只会导致我的应用冻结。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

这个堆栈溢出答案解释了一旦工人完成后打印行只显示的原因:https://stackoverflow.com/a/20818401/1994235

总而言之,在处理跨线程的信号/插槽时,需要使用@pyqtslot(types)来装饰插槽,以确保它们实际上在您想要的线程中运行。

答案 1 :(得分:0)

似乎可以通过继承QThread

轻松完成
class Main(QtGui.QWindow):
  def __init__(self):
    super(Main, self).__init__()
    self.run_button = QtGui.QPushButton("Run")

    mainLayout = QtGui.QVBoxLayout()
    mainLayout.addWidget(self.run_button)
    self.setLayout(mainLayout)

    self.run_button.clicked.connect(self.run_event)

  def run_event(self):
    # Create the dialog to display output
    self.viewer = OutputDialog()

    # Create the worker thread and run it
    self.thread = WorkerThread()
    self.thread.message.connect(self.viewer.write)
    self.thread.start()

class WorkerThread(QtCore.QThread):
  message = QtCore.Signal(str)   

  def run(self):    
    sys.stdout = self


    for i in range(10):
      print "Im doing stuff"
      time.sleep(1)    

  def write(self, text):
    self.message.emit(text)

但是,Web上的大多数文档似乎都建议您不要将QThread子类化,而是使用moveToThread函数来处理任务。

另外,我不知道如何在上述方法中区分stdoutstderr(假设您将两者都重定向到了workerthread)