0

我有一段代码显示一个带有 QTextEdit 字段的 Gui。我想实时打印到该字段,类似于打印功能输出到控制台的方式。

我尝试过使用 append 函数的多个实例。前任:

self.textEdit.append(_translate("MainWindow", ">>> Text", None))

问题是,无论它们在代码中的什么位置,它们似乎只在程序执行后才显示出来。我的目标是让它们像控制台上的打印功能一样显示。

我觉得这是一个简单的答案,但我没有运气搜索.. 我对 Python 还很陌生,任何帮助或指导将不胜感激。

提前致谢!

4

2 回答 2

2

这意味着您可能正在 GUI 线程中完成所有工作。这是一个常见的错误,这意味着当有其他事情发生时,GUI 将冻结并且不响应。

您可以添加一个调用以QApplication.processEvents()允许在您更改QTextEdit.

解决方案很简单:在单独的线程中完成工作。您应该阅读Qt 文档中的Threading Basics,这应该可以帮助您入门。

于 2013-04-23T20:14:55.790 回答
2

事实上,正如 mata 所提到的,冻结来自于在同一个(主)线程中完成所有工作,该线程还处理 UI 更新。解决响应问题的一种方法确实是在阻塞代码中频繁使用 QApplication.processEvents() 。如果足够频繁,这会给用户一个响应式 GUI 的印象。

但是,在 Python 中使用线程(无论是原生线程还是 QThread)并不总是有效。那是因为 Global Interpreter Lock 的存在(GIL,wiki 有一个很好的简短介绍)。简而言之,Python 不允许多个线程同时执行代码。

如果您的后台任务很轻,或者基于 IO,您可以绕过这个问题,因为大多数用于 Python 的 IO 繁重的模块在执行它们的工作时都会释放 GIL。但是,如果您在 Python 中执行大量计算,GIL 将被您的进程锁定,因此您的 UI 仍将无响应。

考虑以下使用 PySide 构建的示例:

import sys, random
from threading import Thread
from time import sleep
from urllib import urlopen
from PySide import QtCore, QtGui

class Window(QtGui.QMainWindow):
    update_signal = QtCore.Signal(int)
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.progress_bar = QtGui.QProgressBar(self)
        self.progress_bar.setRange(0, 10)
        self.setCentralWidget(self.progress_bar)
        self.update_signal[int].connect(self.progress_bar.setValue)
        self.show()
        self.t = Thread(target=self.worker)
        self.t.start()

    def worker(self):
        while self.progress_bar.value() < 10:
            self.update_signal.emit(self.progress_bar.value()+1)
            print "Starting Sleep"
            sleep(5)
            print "End of Sleep"

if __name__ == '__main__':
    qapp = QtGui.QApplication(sys.argv)
    win = Window()
    sys.exit(qapp.exec_())

然后,尝试将工作函数替换为:

def worker(self):
    while self.progress_bar.value() < 10:
        self.update_signal.emit(self.progress_bar.value()+1)
        v = 0
        print "Starting Add"
        for i in xrange(5000000):
            v = v+random.uniform(0, 100)
        print "End of Add"

第一种情况维护响应式 UI,因为对 sleep() 的调用会释放 GIL。但是第二个例子没有,因为计算密集型算法保留了锁。

一种解决方案可能是使用多处理包。从文档:

multiprocessing 是一个使用类似于 threading 模块的 API 支持生成进程的包。multiprocessing 包提供本地和远程并发,通过使用子进程而不是线程来有效地避开全局解释器锁。因此,多处理模块允许程序员充分利用给定机器上的多个处理器。

一个使用 python 多处理的简单说明性示例。

此外,如果您有进一步的兴趣,可能会对这篇关于多处理技术的博文感兴趣。

于 2013-04-23T21:53:39.423 回答