PyQt:从回调函数更新GUI

6
使用Python3和PyQt4,我有一个函数(run),它以可调用的形式作为输入,提供状态更新。
class Windows(QtGui.QWidget):
    # Creates a widget containing:
    # - a QLineEdit (status_widget)
    # - a button, connected to on_run_clicked

    def on_run_clicked(self):
        def update(text):
            self.widget.setText(text)

        threading.Thread(target=run, args=(update, )).start()

这个方法可以正常工作(即文本更新可以在小部件中正确显示)。但是,当我将QLineEdit替换为QTextEdit并使用append方法添加文本时,会出现以下错误:

QObject::connect:无法排队类型为“QTextCursor”的参数

(请确保使用qRegisterMetaType()注册了“QTextCursor”)。

它仍然可以工作,但指出我做错了什么,并且我不确定当有更多线程活动时是否会继续工作。通常,我使用信号和插槽来进行此类更新,但run函数不是PyQt特定的。问题是:

  1. 为什么对于QLineEdit而言没有警告,而对于QTextEdit而言却没有警告?
  2. 如何正确处理这种情况?
1个回答

11

我不知道为什么一个类可以正常工作而另一个则不行,也不太清楚使用Python线程和Qt的线程有什么区别...但是我可以告诉你,如果没有正确设置,它非常容易出现问题。特别是,你不能(或至少不应该)从线程中修改GUI对象。再次强调,不确定Python线程与Qt线程之间的区别。但是,从GUI修改界面的安全方法是通过发送信号到窗口...我所知道的最简单的方法是通过Qt线程实现。

class MyThread(QtCore.QThread):
    updated = QtCore.pyqtSignal(str)

    def run( self ):
        # do some functionality
        for i in range(10000):
            self.updated.emit(str(i))

class Windows(QtGui.QWidget):
    def __init__( self, parent = None ):
        super(Windows, self).__init__(parent)

        self._thread = MyThread(self)
        self._thread.updated.connect(self.updateText)

        # create a line edit and a button

        self._button.clicked.connect(self._thread.start)

    def updateText( self, text ):
        self.widget.setText(text)

3
这个问题是Python vs Qt线程问题的一个很好的起点。执行摘要:当与Qt交互时,始终使用Qt线程;否则,请使用Python线程。 - ekhumoro
当您无法控制运行函数但可以给它回调时,哪种方法是正确的?最简单的方法似乎是在回调函数上执行emit,对吗?此外,这篇文章http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/说您不应该子类化QThread,这也适用于PyQt吗? - Hernan
哦,那很有趣 - 我以前从未见过。我需要更详细地阅读一下。如果不应该子类化QThread,那么他们的文档已经严重过时了... - Eric Hulser
@EricHulser 是的,看来情况是这样的。这里有一篇有趣的 C++ 帖子 http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/。 - Hernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接