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

Python 如何在PyQT5中暂停/播放线程?,python,multithreading,python-multithreading,qthread,pyqt5,Python,Multithreading,Python Multithreading,Qthread,Pyqt5,我正在用PyQT5制作一个轻量级GUI程序 但是现在我面临一些关于线程的问题 我刚刚制作了一个简单的测试程序,如下图: 该程序只是试图将数字附加到文本框,但它崩溃了 我不知道为什么,但我可以通过删除一条评论(time.sleep)来阻止它 如果设定的时间越长越好 我认为这是因为资源访问,因为它是PyQT5GUI 所以我找到了QThread。我试着像屁股一样 import sys import time from PyQt5.QtCore import * from PyQt5.QtWidgets

我正在用PyQT5制作一个轻量级GUI程序

但是现在我面临一些关于线程的问题

我刚刚制作了一个简单的测试程序,如下图:

该程序只是试图将数字附加到文本框,但它崩溃了

我不知道为什么,但我可以通过删除一条评论(time.sleep)来阻止它

如果设定的时间越长越好

我认为这是因为资源访问,因为它是PyQT5GUI

所以我找到了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的信息,您不应该通过多线程直接控制GUI。由于两个不同的线程试图控制GUI,因此会导致冻结或崩溃。 我从这里学到了这个概念

这是您的代码,它将完美地工作

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_())

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

它在哪里崩溃,并与哪个消息?你能不能从这些例子中扔掉更多不必要的东西,让它们变得更简单?@Trilarion,这不是信息。我刚刚意识到这是因为QWidget的线程安全性。谢谢您的评论。顺便说一句@Kaushal您没有使用实际的pyqt5线程模块。您正在使用实际的python线程模块。是否可以使用
QThread
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_())