Search code examples
pythonpyqtpyqt4python-2.6

Can't Update QTextEdit While in a Multiprocess


I am trying to tail a file and output it continuously to a QTextEdit box. However, I have my subprocess and output located within a multiprocess. Here is my code:

shouldRun = True
wMain = QtGui.QWidget()
textboxSideA = QtGui.QTextEdit(wMain)

def tailLog():
    subA = subprocess.Popen(["tail", "-F", "<FILENAME>", stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setsid)
    pollA = select.poll()
    pollA.register(subA.stdout)

    while shouldRun:
        if pollA.poll(1):
            textboxSideA.append(subA.stdout.readline())
    subA.kill()
    os.killpg(subA.pid, signal.SIGKILL)
    return

processSideA = multiprocessing.Process(target = tailLog)
processSideA.start()

wMain.show()

when the textboxSideA.append is called, the textbox doesn't show anything. I have tried just appending a direct string to it just to make sure it wasn't my readline that was bad. However, that wasn't the issue. I then tried to print out my readline directly to the terminal using print(subA.stdout.readline()) which has worked fine. So I concluded that the QTextEdit textbox GUI isn't being updated. I have tried everything and not even Google has given me an answer. Also, I can type in the textbox and that shows up properly, and I can save what I have typed. My GUI just doesn't seem to like the multiprocess as I can call .append() outside of the multiprocess and it works just fine.


Solution

  • Qt does not support multiprocessing so it is dangerous to update the GUI from another process, the GUI can only and should be updated from the thread of the process where it was created.

    On the other hand in this case it is not necessary to use multiprocessing since you can use QProcess:

    import sys
    
    from PyQt4 import QtCore, QtGui
    
    
    class MainWindow(QtGui.QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
            self.process = QtCore.QProcess(self)
            self.process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
            self.process.readyReadStandardOutput.connect(self.on_readyReadStandardOutput)
            self.textedit = QtGui.QTextEdit()
    
            self.setCentralWidget(self.textedit)
    
        def tail(self, filename):
            self.process.kill()
            self.process.start("tail", ["-F", filename])
    
        @QtCore.pyqtSlot()
        def on_readyReadStandardOutput(self):
            msg = self.process.readAllStandardOutput().data().encode()
            self.textedit.append(msg)
    
    
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        w = MainWindow()
        w.tail("<FILENAME>")
        w.show()
        sys.exit(app.exec_())