如何在PyQT5中暂停/播放一个线程?

时间:2015-11-28 07:56:22

标签: python multithreading python-multithreading qthread pyqt5

我正在使用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

2 个答案:

答案 0 :(得分:2)

您不应该通过多线程直接控制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_())

答案 1 :(得分:0)

您可以使用 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_())