简短版:
以突然的方式向GUI发送信号会导致他们携带的数据被插入到他们打算进入的文本框中的所有位置。
长版:
我有一个连接到Python脚本的PyQt GUI。该脚本在单独的线程中运行,并写入stdout
和stderr
。脚本可以独立执行,但我创建了一个GUI,以提供更加用户友好的界面。
为了捕获stdout
/ stderr
并在GUI中写出它们的输出,我在线程中用一个对象覆盖了sys.stdout
和sys.stderr
写方法。
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)
此写入方法向GUI发出信号和消息。 GUI(在主线程中)选择它并分别更新纯文本框(称为consoleOutput
):
self.connect(self.thread, QtCore.SIGNAL('update_console(QString)'), self.ui.consoleOutput.insertPlainText)
我注意到,当stdout
突然出现活动时,输出将以乱码的方式写入GUI(字面上按任意顺序移位但不会覆盖以前的输出)。我也将相同的输出写入控制台,这是完美的顺序。
要解决这个问题,我尝试引入互斥锁,但无济于事。然后我引入了一个延迟(通过调用time.sleep(0.5)
),这解决了问题,虽然是以一种愚蠢的方式。
在查看信号发射和顺序之后,看起来信号按发射顺序处理(我没有覆盖任何标准行为),因此顺序可能不是问题。
有什么想法吗?
修改:
我创建了一个可编辑的示例,其中包含三个需要位于同一目录中的文件:
可编辑示例将随机数据与计数器一起打印到屏幕以跟踪打印的顺序。此screenshot表示某些数据与其他数据不同步。
答案 0 :(得分:2)
事实证明,解决方案比我想象的更简单,更简单。
基本上,问题是我必须手动移动光标在之前和之后插入文本。
我所遵循的解决方案详细here:
为了在我的情况下实现它,我首先通过在方法(updateConsole
)中包装插入调用来更新接收信号的插槽:
self.connect(self.fpga_thread, QtCore.SIGNAL('update_console(QString)'), self.updateConsole)
看起来像这样:
def updateConsole(self, msg):
self.ui.consoleOutput.moveCursor(QtGui.QTextCursor.End)
self.ui.consoleOutput.insertPlainText(msg)
self.ui.consoleOutput.moveCursor(QtGui.QTextCursor.End)
现在它可以工作,似乎问题与滚动有关。如果我在更新时滚动文本框(不手动移动光标),则将文本放在当前显示文本的底部(而不是文本框的底部)。
毕竟我没有引入延迟并删除了sleep
但我保留了互斥锁以防万一。