Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@rbonvall
Created April 4, 2014 20:36
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save rbonvall/9982648 to your computer and use it in GitHub Desktop.
Save rbonvall/9982648 to your computer and use it in GitHub Desktop.
Redirect both stdin and stdout of a process to a PyQt text edit.
from PyQt4 import QtGui, QtCore, uic
def p(x):
print x
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QWidget.__init__(self)
uic.loadUi('redirect.ui', self)
print 'Connecting process'
self.process = QtCore.QProcess(self)
self.process.readyReadStandardOutput.connect(self.stdoutReady)
self.process.readyReadStandardError.connect(self.stderrReady)
self.process.started.connect(lambda: p('Started!'))
self.process.finished.connect(lambda: p('Finished!'))
print 'Starting process'
self.process.start('python', ['speak.py'])
def append(self, text):
cursor = self.textEdit.textCursor()
cursor.movePosition(cursor.End)
cursor.insertText(text)
#self.output.ensureCursorVisible()
def stdoutReady(self):
text = str(self.process.readAllStandardOutput())
print text.strip()
self.append(text)
def stderrReady(self):
text = str(self.process.readAllStandardError())
print text.strip()
self.append(text)
def main():
import sys
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextEdit" name="textEdit">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
from time import sleep
from random import randrange, choice
from sys import stderr, stdout
def main():
options = 2 * ['good'] + ['bad']
with open('log.txt', 'w') as f:
for i in range(10):
sleep(randrange(1, 3))
option = choice(options)
if option == 'good':
stdout.write('good\n')
stdout.flush()
else:
stderr.write('bad\n')
stderr.flush()
f.write(option + '\n')
f.flush()
if __name__ == '__main__':
main()
@arindam31
Copy link

If I need to call an internal function instead of an external python file, how should I replace the statement:

self.process.start('python', ['speak.py'])

@VicDaAr
Copy link

VicDaAr commented Feb 13, 2020

Thanks! Your code helped me a lot, i had to update them for Python3, so i'm leaving them here

redirect3.py

from PyQt5 import QtWidgets, QtCore, uic

def p(x):
    print (x)

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        uic.loadUi('redirect.ui', self)

        print ('Connecting process')
        self.process = QtCore.QProcess(self)
        self.process.readyRead.connect(self.stdoutReady) #alternative to use print('',flush=True) instead of stdout
        
        #self.process.readyReadStandardOutput.connect(self.stdoutReady)
        #self.process.readyReadStandardError.connect(self.stderrReady)
        self.process.started.connect(lambda: p('Started!'))
        self.process.finished.connect(lambda: p('Finished!'))

        print ('Starting process')
        self.process.start('python', ['speak.py'])

    def append(self, text):
        cursor = self.textEdit.textCursor()
        cursor.movePosition(cursor.End)
        cursor.insertText(text)
        #self.output.ensureCursorVisible()

    def stdoutReady(self):
        text = str(self.process.readAllStandardOutput())
        print (text.strip())
        self.append('\n' + text)

    def stderrReady(self):
        text = str(self.process.readAllStandardError())
        #print (text.strip())
        self.append(text)


def main():
    import sys
    app = QtWidgets.QApplication(sys.argv)
    win = MainWindow()
    win.show()
    sys.exit(app.exec_())
    
if __name__ == '__main__':
    main()

speak.py

from time import sleep
from random import randrange, choice
from sys import stderr, stdout

def main():
    options = 2 * ['good'] + ['bad']
    with open('log.txt', 'w') as f:
        for i in range(10):
            sleep(randrange(1, 3))
            option = choice(options)
            if option == 'good':
                #stdout.write('good')
                #stdout.flush()
                pf('good', end='')
            else:
                #stderr.write('bad')
                #stderr.flush()
                pf('bad', end='')
        sleep(1)
        pf('end of speak', end='')
            #f.write(option + '\n')
            #f.flush()

def pf(string, **kwargs): #if you want to use print('',flush = True) instead of stdout or stderr
    if 'flush' in kwargs:
        print(string, **kwargs)
    else:
        print(string, flush = True, **kwargs)

if __name__ == '__main__':
    main()

ProcessClass.py

from PyQt5 import QtWidgets, QtCore

class PYQT_Process():
    def __init__(self, qmainwindow : QtWidgets.QMainWindow, qtextedit : QtWidgets.QTextEdit, script_for_process : str): 
        self.qmainwindow = qmainwindow
        self.qtextedit = qtextedit
        self.script = script_for_process
        
    def begin_process(self):
        print('Connecting Process')
        self.process =QtCore.QProcess(self.qmainwindow)
        self.process.readyRead.connect(lambda: self.stdoutReady())
        #self.process.readyReadStandardOutput.connect(self.stdoutReady)
        #self.process.readyReadStandardError.connect(lambda: self.stderrReady())
        self.process.started.connect(lambda: print('Started!'))
        self.process.finished.connect(lambda: print('Finished!'))

        print('Starting process')
        self.process.start('python', [self.script])
        
    def append(self, text):
        cursor = self.qtexedit.textCursor()
        cursor.movePosition(cursor.End)
        cursor.insertText(text)
        #self.qmainwindow.output.ensureCursorVisible()

    def stdoutReady(self):
        text = str(self.process.readAllStandardOutput())
        #print('out')
        #print(text.strip())
        self.qtextedit.append(text)

    def stderrReady(self):
        text = str(self.process.readAllStandardError())
        #print('error')
        #print(text.strip())
        self.qtextedit.append(text)

@ggdewilly
Copy link

ggdewilly commented Nov 13, 2020

Huge thanks to both of you guys
I borrow all the code from yours and made it PySide2
Posted here for those who might need it, hope I didn't miss anything

| redirect3.py - very few changes

from PySide2 import QtWidgets, QtCore
from redirect_ui import Ui_MainWindow

def p(x):
print (x)

class MainWindow(QtWidgets.QMainWindow):
def init(self, parent=None):
super(MainWindow, self).init(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)

    print ('Connecting process')
    self.process = QtCore.QProcess(self)
    self.process.readyRead.connect(self.stdoutReady) #alternative to use print('',flush=True) instead of stdout
    
    #self.process.readyReadStandardOutput.connect(self.stdoutReady)
    #self.process.readyReadStandardError.connect(self.stderrReady)
    self.process.started.connect(lambda: p('Started!'))
    self.process.finished.connect(lambda: p('Finished!'))

    print ('Starting process')
    self.process.start('python', ['speak.py'])

def append(self, text):
    cursor = self.ui.textEdit.textCursor()
    cursor.movePosition(cursor.End)
    cursor.insertText(text)
    #self.output.ensureCursorVisible()

def stdoutReady(self):
    text = str(self.process.readAllStandardOutput())
    print (text.strip())
    self.append('\n' + text)

def stderrReady(self):
    text = str(self.process.readAllStandardError())
    #print (text.strip())
    self.append(text)

def main():
import sys
app = QtWidgets.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())

if name == 'main':
main()

| speak.py - no changes

from time import sleep
from random import randrange, choice
from sys import stderr, stdout

def main():
options = 2 * ['good'] + ['bad']
with open('log.txt', 'w') as f:
for i in range(10):
sleep(randrange(1, 3))
option = choice(options)
if option == 'good':
#stdout.write('good')
#stdout.flush()
pf('good', end='')
else:
#stderr.write('bad')
#stderr.flush()
pf('bad', end='')
sleep(1)
pf('end of speak', end='')
#f.write(option + '\n')
#f.flush()

def pf(string, **kwargs): #if you want to use print('',flush = True) instead of stdout or stderr
if 'flush' in kwargs:
print(string, **kwargs)
else:
print(string, flush = True, **kwargs)

if name == 'main':
main()

| ProcessClass.py - only change PySide2

from PySide2 import QtWidgets, QtCore

class PYQT_Process():
def init(self, qmainwindow : QtWidgets.QMainWindow, qtextedit : QtWidgets.QTextEdit, script_for_process : str):
self.qmainwindow = qmainwindow
self.qtextedit = qtextedit
self.script = script_for_process

def begin_process(self):
    print('Connecting Process')
    self.process =QtCore.QProcess(self.qmainwindow)
    self.process.readyRead.connect(lambda: self.stdoutReady())
    #self.process.readyReadStandardOutput.connect(self.stdoutReady)
    #self.process.readyReadStandardError.connect(lambda: self.stderrReady())
    self.process.started.connect(lambda: print('Started!'))
    self.process.finished.connect(lambda: print('Finished!'))

    print('Starting process')
    self.process.start('python', [self.script])
    
def append(self, text):
    cursor = self.qtexedit.textCursor()
    cursor.movePosition(cursor.End)
    cursor.insertText(text)
    #self.qmainwindow.output.ensureCursorVisible()

def stdoutReady(self):
    text = str(self.process.readAllStandardOutput())
    #print('out')
    #print(text.strip())
    self.qtextedit.append(text)

def stderrReady(self):
    text = str(self.process.readAllStandardError())
    #print('error')
    #print(text.strip())
    self.qtextedit.append(text)

| redirect_ui.py - new generated file - see bellow

from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *

class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.verticalLayout = QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName(u"verticalLayout")
self.textEdit = QTextEdit(self.centralwidget)
self.textEdit.setObjectName(u"textEdit")
font = QFont()
font.setPointSize(12)
self.textEdit.setFont(font)
self.textEdit.setReadOnly(True)

    self.verticalLayout.addWidget(self.textEdit)

    MainWindow.setCentralWidget(self.centralwidget)
    self.statusbar = QStatusBar(MainWindow)
    self.statusbar.setObjectName(u"statusbar")
    MainWindow.setStatusBar(self.statusbar)

    self.retranslateUi(MainWindow)

    QMetaObject.connectSlotsByName(MainWindow)
# setupUi

def retranslateUi(self, MainWindow):
    MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
# retranslateUi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment