Short version:
Sending signals to GUI in a sudden manner causes data they carry to be inserted all over the place in the textbox they're meant to go in.
Long version:
I have a PyQt GUI which is connected to a Python script. The script is run in a separate thread and it writes to stdout
and stderr
. Script can execute independently but I created a GUI to provide a more user-friendly interface.
In order to capture stdout
/stderr
and write their output in the GUI, I've overwritten sys.stdout
and sys.stderr
in the thread with an object that has a write method.
sys.stdout = StreamWrapper(sys.stdout, self, self.mutex)
sys.stderr = StreamWrapper(sys.stderr, self, self.mutex)
StreamWrapper:
class StreamWrapper:
def __init__(self, stream, thread, mutex):
self.stream = stream # reference to original stream (stdout or stderr)
self.thread = thread # thread in which this object is initialised.
self.mutex = mutex # mutex ensuring write is only called once at a time
def write(self, msg):
with QtCore.QMutexLocker(self.mutex):
self.thread.emit(QtCore.SIGNAL('update_console(QString)'), msg)
self.stream.write(msg)
time.sleep(0.5)
This write method emits a signal and a message to the GUI. The GUI (in the main thread) picks it up and updates a plain text box respectively (called consoleOutput
):
self.connect(self.thread, QtCore.SIGNAL('update_console(QString)'), self.ui.consoleOutput.insertPlainText)
I noticed that when there's a sudden burst of activity from stdout
, the output will be written in a jumbled up manner in the GUI (literally in any order and displacing but not overwriting previous output). I also write the same output to the console, and this is in perfect order.
To fix it I tried introducing a mutex but to no avail. I then introduced a delay (by way of calling time.sleep(0.5)
) and this fixed the problem, albeit in a kludgy manner.
Having looked at signal emitting and order it looks like signals are processed in the order that they are emitted (I'm not overriding any standard behaviour) so order might not be the issue.
Any ideas?
EDIT:
I've created a compilable example consisting of three files that need to be in the same directory:
The compilable example prints random data to screen along with a counter to track the order of the prints. This screenshot shows that some of the data is out of sync with the rest.