信号和插槽PyQt澄清

问题描述 投票:0回答:2

我注意到有许多用户,包括我自己,他们并不完全掌握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
2个回答
2
投票

您得到该错误的原因正是错误消息所描述的原因 - 信号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的任何方法
  • 如果需要在线程之间传递数据,信号也可以发送数据

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。

© www.soinside.com 2019 - 2024. All rights reserved.