如何打印到QTextEdit以模仿打印到控制台? (Python 3.3)

时间:2013-04-23 19:24:13

标签: python python-3.x pyqt pyqt4 python-3.3

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

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

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

问题在于,无论代码在何处,它们似乎只在程序执行后显示。我的目标是让它们像控制台上的打印功能那样显示在线。

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

提前致谢!

2 个答案:

答案 0 :(得分:2)

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

您可以添加对QApplication.processEvents()的调用以允许在更改QTextEdit中的文本后更新GUI,但这只能部分解决问题,但GUI之间会冻结那些电话。

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

答案 1 :(得分:2)

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

但是,在Python中使用线程(无论是本机还是QThread)并不总是有效。这是因为Global Interpreter Lock(GIL,the wiki has a good short intro)的存在。简而言之,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_())

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

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包。 来自文档:

  

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

A simple, illustrative example of using python multipocessing.

此外,如果您有兴趣,可能会对this blog post about multi-processing techniques感兴趣。