简体   繁体   English

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

[英]How to pause/play a thread in PyQT5?

I'm making a light GUI program with PyQT5.我正在用 PyQT5 制作一个轻量级的 GUI 程序。

But now I'm facing some problem about thread.但是现在我面临着一些关于线程的问题。

I just made simple test program like bottom:我只是做了一个简单的测试程序,比如底部:

the program simply trying to append numbers to textbox, but it crashes.该程序只是试图将数字附加到文本框,但它崩溃了。

I don't know why but somehow I can prevent it by removing a comment(time.sleep)我不知道为什么但不知何故我可以通过删除评论来防止它(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_())

It would be better if sets time higher.如果时间设置得高一些会更好。

I thought it is because of resource accessing, since it is pyQT5 GUI.我认为这是因为资源访问,因为它是pyQT5 GUI。

So I've find QThread.所以我找到了 QThread。 and I tried like bottom,我试着像底部一样,

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

But crashes, doesn't work.但崩溃,不起作用。 and tried QThread+threading.Event().并尝试了 QThread+threading.Event()。 It freezes GUI.它冻结了 GUI。

Now I don't know how to proceed it...现在不知道怎么处理了...

Edit: I just realized about thread.编辑:我刚刚意识到线程。 Should not be accessed from other thread except QThread.不应从除 QThread 之外的其他线程访问。 Then I will keep find about QWaitCondition然后我会继续查找 QWaitCondition

You should not control GUI directly via multithreading.您不应该通过多线程直接控制 GUI。 Since two different threads are trying to control the GUI this results to freeze or crash.由于两个不同的线程试图控制 GUI,这会导致冻结或崩溃。 I have learnt about this concept from here http://www.xyzlang.com/python/PyQT5/pyqt_multithreading.html我从这里了解了这个概念http://www.xyzlang.com/python/PyQT5/pyqt_multithreading.html

Here is your code that will work perfectly.这是您可以完美运行的代码。

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

You can pause the loop by using while = True and you can stop the loop with break statement您可以使用 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_())

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

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