如何在 PyQT5 中暂停/播放线程?
Posted
技术标签:
【中文标题】如何在 PyQT5 中暂停/播放线程?【英文标题】:How to pause/play a thread in PyQT5? 【发布时间】:2015-11-28 07:56:22 【问题描述】:我正在用 PyQT5 制作一个轻量级的 GUI 程序。
但是现在我遇到了一些关于线程的问题。
我只是做了一个简单的测试程序,比如底部:
程序只是试图将数字附加到文本框,但它崩溃了。
我不知道为什么,但我可以通过删除评论来阻止它(time.sleep)
import sys
import threading
import time
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Some(QWidget):
e = threading.Event()
def btnfunc(self):
self.e.set()
def __init__(self):
super().__init__()
self.myButton = QPushButton('do next')
self.logs = QTextEdit()
self.mylay = QVBoxLayout()
self.mylay.addWidget(self.myButton)
self.mylay.addWidget(self.logs)
self.setLayout(self.mylay)
self.setGeometry(300, 300, 300, 550)
self.setWindowTitle('mytest')
self.show()
t = threading.Thread(target=self.myfunc, args=( ))
t.start()
self.myButton.clicked.connect(self.btnfunc)
def myfunc(self):
for i in range(300):
# time.sleep(0.4)
self.logs.append(str(i))
if i == 20:
self.e.wait()
app = QApplication(sys.argv)
ex = Some()
sys.exit(app.exec_())
如果设置时间更高会更好。
我以为是资源访问的原因,因为它是 pyQT5 GUI。
所以我找到了 QThread。我试着像底部一样,
import sys
import time
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Some(QWidget):
qw = QWaitCondition()
qm = QMutex()
def btnfunc(self):
self.qw.wakeAll()
def __init__(self):
super().__init__()
self.myButton = QPushButton('do next')
self.logs = QTextEdit()
self.mylay = QVBoxLayout()
self.mylay.addWidget(self.myButton)
self.mylay.addWidget(self.logs)
self.setLayout(self.mylay)
self.setGeometry(300, 300, 300, 550)
self.setWindowTitle('mytest')
self.show()
self.myButton.clicked.connect(self.btnfunc)
self.thread = QThread()
self.thread.started.connect(self.myfunc)
self.thread.start()
def myfunc(self):
for i in range(300):
self.logs.append(str(i))
if i == 20:
self.qw.wait(self.qm)
app = QApplication(sys.argv)
ex = Some()
sys.exit(app.exec_())
但是崩溃,不起作用。并尝试了 QThread+threading.Event()。它冻结了 GUI。
现在不知道怎么办了……
编辑: 我刚刚意识到线程。不应从除 QThread 之外的其他线程访问。 那我就继续找QWaitCondition
【问题讨论】:
它在哪里崩溃以及出现什么消息?你能不能从例子中去掉更多不必要的东西,让它们变得更容易? @Trilarion 这不是来自消息。我刚刚意识到这是因为 QWidget 的线程安全。顺便说一句,感谢您的评论。 【参考方案1】:您不应该通过多线程直接控制 GUI。由于两个不同的线程试图控制 GUI,这会导致冻结或崩溃。 我从这里了解了这个概念http://www.xyzlang.com/python/PyQT5/pyqt_multithreading.html
这是您可以完美运行的代码。
import sys
import threading
import time
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
# Added new
class Communicate(QObject):
signal = pyqtSignal(str)
class Some(QWidget):
e = threading.Event()
def btnfunc(self):
self.e.set()
def __init__(self):
super().__init__()
#communicate object
self.comm = Communicate()
self.comm.signal.connect(self.append_data)
self.myButton = QPushButton('do next')
self.logs = QTextEdit()
self.mylay = QVBoxLayout()
self.mylay.addWidget(self.myButton)
self.mylay.addWidget(self.logs)
self.setLayout(self.mylay)
self.setGeometry(300, 300, 300, 550)
self.setWindowTitle('mytest')
self.show()
t = threading.Thread(target=self.myfunc, args=( ))
t.start()
self.myButton.clicked.connect(self.btnfunc)
def myfunc(self):
for i in range(300):
# time.sleep(0.4)
#self.logs.append(str(i))
self.comm.signal.emit(str(i))
if i == 20:
self.e.wait()
def append_data(self, data):
self.logs.append(data)
app = QApplication(sys.argv)
ex = Some()
sys.exit(app.exec_())
【讨论】:
@Kaushal 您没有使用实际的 pyqt5 线程模块。您正在使用实际的 python 线程模块。可以使用QThread
吗?【参考方案2】:
您可以使用 while = True 暂停循环,也可以使用 break 语句停止循环
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import (
Qt, QObject, pyqtSignal, pyqtSlot, QRunnable, QThreadPool
)
import time
from time import sleep
import threading
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(655, 589)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.run = QtWidgets.QPushButton(self.centralwidget)
self.run.setGeometry(QtCore.QRect(260, 50, 93, 28))
self.run.setObjectName("run")
self.result = QtWidgets.QTextEdit(self.centralwidget)
self.result.setGeometry(QtCore.QRect(110, 120, 491, 201))
self.result.setObjectName("result")
self.stop = QtWidgets.QPushButton(self.centralwidget)
self.stop.setGeometry(QtCore.QRect(110, 390, 93, 28))
self.stop.setObjectName("stop")
self.pause = QtWidgets.QPushButton(self.centralwidget)
self.pause.setGeometry(QtCore.QRect(300, 390, 93, 28))
self.pause.setObjectName("pause")
self.resume = QtWidgets.QPushButton(self.centralwidget)
self.resume.setGeometry(QtCore.QRect(480, 390, 93, 28))
self.resume.setObjectName("resume")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 655, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.run.setText(_translate("MainWindow", "Run"))
self.stop.setText(_translate("MainWindow", "stop"))
self.pause.setText(_translate("MainWindow", "Pause"))
self.resume.setText(_translate("MainWindow", "Resume"))
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.is_paused = False
self.is_killed = False
self.run.clicked.connect(self.send_wala)
self.stop.clicked.connect(self.kill_g)
self.pause.clicked.connect(self.pause_g)
self.resume.clicked.connect(self.resume_g)
@QtCore.pyqtSlot()
def send_wala(self):
threading.Thread(target=self.working, daemon=True).start()
def working(self):
for i in range(10):
sleep(3)
self.result.append(str(i))
while self.is_paused:
time.sleep(0)
if self.is_killed:
break
def pause_g(self):
self.is_paused = True
def resume_g(self):
self.is_paused = False
def kill_g(self):
self.is_killed = True
import sys
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
【讨论】:
以上是关于如何在 PyQT5 中暂停/播放线程?的主要内容,如果未能解决你的问题,请参考以下文章
如何在其他视图中使用 Swift 中的 AVPlayer 暂停和播放音乐