0

I've implemented this answer into my code, which I was hoping would do what I want. However, I'm running a method via a connection on a QPushButton, and I want to pipe what happens in this method to the GUI.

The first time I click the button the stdout appears in the interpreter window; however, on subsequent presses of the button, the stdout appears in the QTextEdit - I assume there's some intricacy of the print statement, or of QPushButton, that I don't understand - if anyone can give any pointers where I need to start changing my code I'll be eternally grateful!

I think this is the smallest amount of code I can use to demonstrate the problem..

import os, sys
from PyQt4 import QtCore, QtGui 

def main(): 
  app = QtGui.QApplication(sys.argv) 
  w = MyWindow() 
  w.show() 
  sys.exit(app.exec_()) 

class MyWindow(QtGui.QWidget): 
  def __init__(self, *args): 
    QtGui.QWidget.__init__(self, *args) 
    self.runBtn = QtGui.QPushButton('Run!', self)
    self.runBtn.clicked.connect(self.runCmd)
    self.te = QtGui.QTextEdit()

    layout = QtGui.QVBoxLayout(self)
    layout.addWidget(self.runBtn)
    layout.addWidget(self.te)
    self.setLayout(layout) 

  def runCmd(self):
    print "here"
    print sys.stdout
    sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)

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

  def normalOutputWritten(self, text):
    cursor = self.te.textCursor()
    cursor.movePosition(QtGui.QTextCursor.End)
    cursor.insertText(text)
    self.te.setTextCursor(cursor)
    self.te.ensureCursorVisible()

class EmittingStream(QtCore.QObject):
  textWritten = QtCore.pyqtSignal(str)
  def write(self, text):
    self.textWritten.emit(str(text))

if __name__ == "__main__": 
  main()
Community
  • 1
  • 1
ChrisW
  • 4,970
  • 7
  • 55
  • 92

2 Answers2

1

You're mixing signals with method calls:

sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)

I'm not sure what this is supposed to do. You should do this instead:

self.stream = EmittingStream()
self.stream.textWritten.connect(self.normalOutputWritten)

but only once when you start the program. When you want to see the output, do this:

try:
   sys.stdout = self.stream

   ... code to print something ...
finally:
   sys.stdout = sys.__stdout__ # reset stdout to default
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • I don't understand it either... it was taken *ad verbatim* from the answer I linked to (although your point does seem to make some sense - I'm still trying to get my head round PyQt stuff!) – ChrisW Nov 07 '13 at 15:58
  • Maybe it's a bug; the comments say "answers on Stack Overflow are meant to transport ideas, not ready-to-use implementations." – Aaron Digulla Nov 07 '13 at 16:01
  • I've tried using your suggestion, and get a `AttributeError: 'PyQt4.QtCore.pyqtSignal' object has no attribute 'connect'` error: I assume you meant `self.stream.textWritten.connect(self.normalOutputWritten)` (which works) – ChrisW Nov 07 '13 at 16:42
0

Aaron made a very good point, but my problem had a much simpler answer than the intricacies of object orientation in python...

sys.stdout = EmittingStream(textWritten=self.normalOutputWritten) 

needs to be after any print statements - print statements before this will be directed to the standard stdout, i.e. the interpreter console.

ChrisW
  • 4,970
  • 7
  • 55
  • 92
  • Err... what? What's the point of setting `sys.stdout` if you're not allowed to print anything? – Aaron Digulla Nov 08 '13 at 09:16
  • I'm sorry, I don't understand your question? – ChrisW Nov 08 '13 at 12:58
  • In your answer, you write "after any print statements" which means nothing will ever be printed via `EmittingStream`. – Aaron Digulla Nov 08 '13 at 14:08
  • there's obviously something I haven't been very clear about (and I don't understand PyQt enough to know what to clarify), but in my code, print statements get directed to stdout until `sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)` is called – ChrisW Nov 08 '13 at 14:55