繁体   English   中英

PyQt5:如何向工作线程发送信号

[英]PyQt5: How to send a signal to a worker thread

我知道如何将信号从工作线程发送回主 GUI 线程,但如何将信号从主线程发送到工作线程?

这是一些包含信号和槽的示例代码。 在这里,我将信号发送回主线程,但是我怎样才能在相反的方向上发送 go 呢?

这里的目标是发送信号以在我希望线程停止时将 self.do 的值更改为 0。

这是主文件,我将把 UI 文件放在下面

from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
from progressUI import Ui_Form

import sys
import time

class ProgressBar(QObject):
    progress = pyqtSignal(int)
    kill = pyqtSignal()

    def __init__(self, timer, parent=None):
        super(ProgressBar, self).__init__(parent)
        self.time = timer
        self.do = 1

    def work(self):

        while self.do == 1:
            y = 0
            for _ in range(100):
                time.sleep(.1)
                y += 1
                self.progress.emit(y)
            break

        self.kill.emit()

    @pyqtSlot(str)
    def worker_slot(self, sentence):
        print(sentence)

class Go(QMainWindow, Ui_Form, QObject):
    custom_signal = pyqtSignal(str)

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setupUi(self)
        self.progressBar.setValue(0)
        self.startThread()

    @pyqtSlot(int)
    def updateProgress(self, val):
        self.progressBar.setValue(val)
        self.custom_signal.emit('hi from main thread')

    def startThread(self):
        self.progressThread = ProgressBar(60)
        self.thread = QThread()
        self.progressThread.moveToThread(self.thread)

        self.progressThread.progress.connect(self.updateProgress)
        self.progressThread.kill.connect(self.thread.quit)
        self.custom_signal.connect(self.progressThread.worker_slot)
        self.thread.started.connect(self.progressThread.work)

        self.thread.start()



if __name__ == '__main__':
     app = QtWidgets.QApplication(sys.argv)
     MainApp = Go()
     MainApp.show()
     sys.exit(app.exec_())

这是用户界面文件。

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(658, 118)
        self.progressBar = QtWidgets.QProgressBar(Form)
        self.progressBar.setGeometry(QtCore.QRect(30, 40, 601, 23))
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName("progressBar")
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(45, 75, 581, 26))
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setObjectName("label")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.label.setText(_translate("Form", "TextLabel"))

你如何向工人线程发送信号? 与从工作线程向GUI发送信号的方式完全相同。 我预计它会更加不同。

@ three-pineapples链接到主线程和工作线程之间的双向通信的一个很好的例子。

如果要在主GUI线程中创建自定义信号,则需要确保继承QObject,然后才能创建自定义信号。

我在原始帖子中更新了我的代码以包含UI文件以便您可以运行它,并且我在GUI线程中包含了一个自定义信号的示例,该信号向工作人员发送信号。

但是,在for循环结束之前你不会看到print语句的输出,因为它阻止了worker处理信号,就像@ three-pineapples所说的那样。

所以,虽然这不是最好的例子,但希望如果有人在理解这个概念时遇到同样的麻烦,也许这会有所帮助。

您好在另一种类型的项目中遇到了同样的问题,请参阅PyQt5 unable to stop/kill QThread

在这里找到了非常有用的解决方案/解释: Stopping an infinite loop in a worker thread in PyQt5 最简单的方法并尝试使用第二个建议的解决方案:解决方案 2:将可变变量作为控制变量传递,选择这个,因为我的项目没有无限循环,但是一个 for 循环运行直到一个目录被清空所有是 subolders/files。

要尝试了解它是如何工作的,请查看我的结果,将其应用于上面的代码:

用户界面文件progressUI_2.py

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(658, 218)
        self.progressBar = QtWidgets.QProgressBar(Form)
        self.progressBar.setGeometry(QtCore.QRect(30, 40, 581, 23))
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName("progressBar")
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(45, 75, 581, 26))
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setObjectName("label")
        
        self.button = QtWidgets.QPushButton('press here', Form)
        self.button.setGeometry(QtCore.QRect(30, 115, 581, 26))
        
        self.button.setObjectName("button")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.label.setText(_translate("Form", "TextLabel"))

主脚本文件main.py

from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
from progressUI_2 import Ui_Form

import sys
import time

class ProgressBar(QObject):
    progress = pyqtSignal(int)
    kill = pyqtSignal()

    def __init__(self, timer, ctrl, parent=None):
        super(ProgressBar, self).__init__(parent)
        self.time = timer
        self.do = 1
        
        self.flag = 'off'
        
        self.ctrl = ctrl # dict with your control var
        


    def work(self):
        
        print('Entered run in worker thread')
        print('id of ctrl in worker:', id(self.ctrl))
        self.ctrl['break'] = False

        while self.do == 1:
            y = 0
            for _ in range(100):
                time.sleep(.1)
                y += 1
                self.progress.emit(y)
                
                if self.flag == 'on':
                    break
                # print('flag : ', self.flag, 'self.do : ', self.do)
                
                if self.ctrl['break'] == True :
                    break
                
            break

        # self.kill.emit()
        
    @pyqtSlot(str)
    def worker_slot2(self, sentence2):
        self.flag = 'on'
        self.do = 0
        print('from worker !!!!', sentence2, 'self.flag : ', self.flag,'self.do : ', self.do)   
        

    @pyqtSlot(str)
    def worker_slot(self, sentence):
        print(sentence)

class Go(QMainWindow, Ui_Form, QObject):
    custom_signal = pyqtSignal(str)
    button_signal = pyqtSignal(str)

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setupUi(self)
        self.progressBar.setValue(0)
        
        
        
        self.button.clicked.connect(self.clicked)
        
        self.ctrl = {'break': False} # dict with your control variable
        print('id of ctrl in main:', id(self.ctrl))
        
        self.startThread()
        
    def clicked(self):
        print('clicked')
        self.button_signal.emit('emitted from go ')
        self.flag = 'on'
        self.do = 0
        # self.ctrl['break'] = True

    @pyqtSlot(int)
    def updateProgress(self, val):
        self.progressBar.setValue(val)
        self.custom_signal.emit('hi from main thread')

    def startThread(self):
        self.progressThread = ProgressBar(60, self.ctrl)
        self.thread = QThread()
        self.progressThread.moveToThread(self.thread)

        self.progressThread.progress.connect(self.updateProgress)
        self.progressThread.kill.connect(self.thread.quit)
        self.custom_signal.connect(self.progressThread.worker_slot)
        
        self.thread.started.connect(self.progressThread.work)
        
        self.button_signal.connect(self.progressThread.worker_slot2)
        
        
        self.thread.start()



if __name__ == '__main__':
     app = QtWidgets.QApplication(sys.argv)
     MainApp = Go()
     MainApp.show()
     sys.exit(app.exec_())

尝试运行main.py

注释掉和取消注释self.ctrl['break'] = True

在:

 def clicked(self):
        print('clicked')
        self.button_signal.emit('emitted from go ')
        self.flag = 'on'
        self.do = 0
        # self.ctrl['break'] = True

看看你是否能够停止按下 QBButton 的进度条,

请注意如何尝试更改代码的各个部分中的self.doself.flag被证明是不成功的,不确定是否只是因为我应该将它们传递给工作人员

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM