我正在尝试在密集进程运行时在PyQt5 QMainWindow上显示加载gif。 QMovie暂停,而不是正常播放。据我所知,事件循环不应被阻止,因为密集进程在其自己的QObject中传递给它自己的QThread。相关代码如下:
的QMainWindow:
class EclipseQa(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.initUI()
def initUI(self):
...
self.loadingMovie = QMovie("./loading.gif")
self.loadingMovie.setScaledSize(QSize(149, 43))
self.statusLbl = QLabel(self)
self.statusLbl.setMovie(self.loadingMovie)
self.grid.addWidget(self.statusLbl, 6, 2, 2, 2, alignment=Qt.AlignCenter)
self.statusLbl.hide()
...
def startLoadingGif(self):
self.statusLbl.show()
self.loadingMovie.start()
def stopLoadingGif(self):
self.loadingMovie.stop()
self.statusLbl.hide()
def maskDose(self):
self.startLoadingGif()
# Set up thread and associated worker object
self.thread = QThread()
self.worker = DcmReadWorker()
self.worker.moveToThread(self.thread)
self.worker.finished.connect(self.thread.quit)
self.worker.updateRd.connect(self.updateRd)
self.worker.updateRs.connect(self.updateRs)
self.worker.updateStructures.connect(self.updateStructures)
self.worker.clearRd.connect(self.clearRd)
self.worker.clearRs.connect(self.clearRs)
self.thread.started.connect(lambda: self.worker.dcmRead(caption, fname[0]))
self.thread.finished.connect(self.stopLoadingGif)
self.maskThread.start()
def showDoneDialog(self):
...
self.stopLoadingGif()
...
工人阶级:
class DoseMaskWorker(QObject):
clearRd = pyqtSignal()
clearRs = pyqtSignal()
finished = pyqtSignal()
startLoadingGif = pyqtSignal()
stopLoadingGif = pyqtSignal()
updateMaskedRd = pyqtSignal(str)
def __init__(self, parent=None):
QObject.__init__(self, parent)
@pyqtSlot(name="maskDose")
def maskDose(self, rd, rdName, rdId, rs, maskingStructure_dict):
...
self.updateMaskedRd.emit(maskedRdName)
self.finished.emit()
为简洁起见,' ...'表示我认为可能不相关的代码。
答案 0 :(得分:1)
当发出线程lambda
信号时,使用started
来调用插槽可能会导致它在主线程中执行。您需要做几件事来解决这个问题。
首先,您对pyqtSlot
的使用不包含maskDose
方法的参数类型。您需要更新它以便它。据推测,您还需要对dcmRead
方法执行此操作,您可以从lambda
调用但未包含在代码中。有关详细信息,请参阅documentation。
为了删除lambda的使用,你需要在EclipseQa
类中定义一个新信号和一个新槽。应定义新信号,以便发出dcmRead
方法所需的参数数量,并正确指定类型(此文档也在上面的链接中)。此信号应连接到workers dcmRead
插槽(确保在将worker对象移动到线程后执行此操作,否则您可能会遇到this错误!)。插槽应该不带参数,并连接到线程started
信号。插槽中的代码应该只使用适当的参数发出新信号,然后传递给dcmRead
(例如self.my_new_signal.emit(param1, param2)
)。
注意:您可以通过从要检查的位置打印threading.current_thread().name
来检查使用Python线程模块运行的任何代码(即使使用QThreads)。
注意2:如果您的线程是CPU绑定而不是IO绑定,您可能仍会遇到性能问题,因为Python GIL只允许单个线程在任何时间执行(它会在线程之间定期交换,但是两个线程中的代码都应该运行,可能不是你期望的性能。 QThreads(用C ++实现,理论上可以发布GIL)对此没有帮助,因为它们运行的是Python代码,因此GIL仍然存在。