【问题标题】:Signals and Slots PyQt clarificationSignals and Slots PyQt 说明
【发布时间】:2014-08-17 12:05:55
【问题描述】:

我注意到有很多用户,包括我自己,都不太了解 Qt 中信号和槽的概念。我希望对以下内容有所澄清:

#I have a function that runs as soon as the GUI is built, this takes the information from     
#a list and puts it into a string which is then uploaded to a texbox. At the bottom of this 
#loop, I want it to call a function in the parent thread via signals and slots, as 
#recommended by other users.
class MainWindow(QtGui.QMainWindow):
    #all the code needed to build the GUI
    thread_mythread = threading.Thread(target = self.updateText, args = ())
    thread_mythread.start()

    def clearText(self):
        self.TextEdit.clear()

    def updateText(self):
        self.trigger.connect(self.clearText)

        while True:
            self.trigger.emit()
            NewString = list.pop(0)
            #I think I may have to use append, as setText() is not safe outside of the parent thread
            self.TextEdit.append(NewString)

虽然可能非常不正确,但我尝试使用信号。这是正确的方法吗?我也得到一个错误,说主窗口对象没有属性“触发器”,这是为什么呢?

谢谢。

【问题讨论】:

    标签: python qt pyqt pyqt4 signals-slots


    【解决方案1】:

    您收到该错误的原因正是错误消息中描述的原因 - 信号 trigger 尚未在您的类中的任何地方定义。您需要先定义它,然后才能发出它。

    信号和槽用于不同对象之间的通信。在您的示例中,您尝试在 MainWindow 类中执行所有操作,并且没有与其他对象的交互。您也只需拨打connect() 一次。在实例化要连接在一起的对象后,您通常会在类构造函数中或从主函数中调用它。

    查看http://pyqt.sourceforge.net/Docs/PyQt4/new_style_signals_slots.html,了解如何在 PyQt 中正确使用信号和插槽的一些示例。

    对于线程,使用 QThread 而不是 threading.Thread,因为它更好地与 Qt 框架集成。 This post 展示了一些如何在 PyQt 中使用 QThread 的简单示例。第二种方法(使用moveToThread())被认为是最正确的创建新线程的方法。

    你的问题的基本思路是:

    • 从主线程处理 GUI 操作
    • 在单独的线程中处理阻塞操作(在您的情况下是 while 循环)
    • 从工作线程发出信号以调用主线程中的函数(槽),反之亦然

    还要注意:

    • 您不能从辅助线程调用 QWidget 其后代的任何方法
    • 如果您需要在线程之间传递数据,信号也可以发送数据

    【讨论】:

    • 这很有帮助。我无法在主线程中处理这种检查,因为无限循环将关闭 GUI。不幸的是,单独的线程也不起作用,这是因为您无法访问父线程之外的某些 Qt 元素(例如 textEdit.clear() 方法)。我的示例不是在问题中提供了从工作线程(thread_myThread)发出信号以在主线程中调用函数(clearText())的示例吗? @user3419537
    • 另外,我将如何定义触发器?
    • 这正是您要使用信号和插槽的原因。如果您将 clearText() 定义为插槽并将其连接到工作线程中的信号,则该线程向主线程发出信号以调用 textEdit.clear(),而不是直接调用它。我发布的第一个链接向您展示了如何定义信号(触发器)。只需使用 pyqtSignal()
    【解决方案2】:

    添加到@user3419537 的好答案。一个非常快速的线程示例:

    from PyQt4.QtCore import QObject, pyqtSlot, pyqtSignal, QThread, \
        Q_ARG, Qt, QMetaObject
    
    class MyWorker(QObject):
        # define signal
        clear = pyqtSignal()
        update_text_signal = pyqtSignal(str)  # passes a string back
        finished = pyqtSignal()
    
        def __init__(self, parent=None):
            super(MyWorker, self).__init__(parent)            
    
    
        # Add functions etc.
        @pyqtSlot(list)
        def update_text(self, string_list):
            #Intensive operation
            self.clear.emit()  # moved outside of while
            while(True):
                #This is infinite loop so thread runs forever
                new_string = self.string_list.pop(0)
                self.update_text_signal.emit(new_string)  # Fixed this line
    
            #Finished
            self.finished.emit()
    

    然后在你的 MainWindow 类中

    self.my_thread = QThread()
    self.handler = MyWorker()
    self.handler.moveToThread(self.my_thread)
    self.handler.clear.connect(self.clearText)
    self.handler.update_text_signal.connect(self.update_line_edit)
    self.handler.finished.connect(self.my_thread.quit)
    # Start Thread
    self.my_thread.start()
    
    @pyqtSlot(str)
    def update_line_edit(self, text):
        self.TextEdit.append(text)
    
    QMetaObject.invokeMethod(self.handler, 'update_text',
                             Qt.QueuedConnection,
                             Q_ARG(list, string_list))
    

    您需要在应用程序关闭之前调用self.my_thread.quit() 以停止线程并避免错误:QThread: Destroyed while thread is still running

    请阅读docs 获取 QMetaObject.invokeMethod。

    【讨论】:

    • 这很有帮助,但是它说 update_text 没有属性 connect
    • 对不起。因为我将信号命名为与函数相同的名称,所以它不知道要使用什么。请参阅上面的修改代码。
    • 这就是我的想法,但现在我收到以下消息:QThread: Destroyed while thread is still running 并且我的文本框中没有发生任何可见的操作
    • 我什至在 update_text 函数中放了一个调试语句,但它没有到达它。
    • 再次更改代码。请尝试一下。我目前无法访问 PyQt 环境,因此无法正确测试代码。
    猜你喜欢
    • 2012-07-25
    • 2021-12-14
    • 2012-03-05
    • 2013-06-17
    • 1970-01-01
    • 2022-11-06
    • 2022-12-27
    • 2017-11-26
    • 2021-12-17
    相关资源
    最近更新 更多