【问题标题】:How to run a "While Loop" with PyQt5?如何使用 PyQt5 运行“While Loop”?
【发布时间】:2018-09-27 21:43:24
【问题描述】:

我前段时间制作了一个脚本来记录用户的监视器帧,现在我正在尝试为它创建一个 GUI。目前它只有一个 START 和一个 STOP 按钮,但 STOP 按钮不会停止录制。

如何更改我的stop_thread 函数才能使其正常工作?我应该先终止工人然后终止线程吗?无论如何,我怎样才能终止工人?

import sys
from PyQt5.QtWidgets import (QWidget,
                             QPushButton, QApplication, QGridLayout)
from PyQt5.QtCore import QThread, QObject


class Worker(QObject):

    def __init__(self, parent=None):
        QObject.__init__(self, parent=parent)

    def do_work(self):
        i = 1
        while True:
            print(i)
            QThread.sleep(1)
            i = i + 1

    def stop(self):
        print("stopped")
        self.deleteLater() # How do I stop it?


class Gui(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):

        # Buttons:
        self.btn_start = QPushButton('Start')
        self.btn_start.resize(self.btn_start.sizeHint())
        self.btn_start.move(50, 50)
        self.btn_stop = QPushButton('Stop')
        self.btn_stop.resize(self.btn_stop.sizeHint())
        self.btn_stop.move(150, 50)

        # GUI title, size, etc...
        self.setGeometry(300, 300, 300, 220)
        self.setWindowTitle('ThreadTest')
        self.layout = QGridLayout()
        self.layout.addWidget(self.btn_start, 0, 0)
        self.layout.addWidget(self.btn_stop, 0, 50)
        self.setLayout(self.layout)

        # Thread:
        self.thread = QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.thread)

        self.thread.started.connect(self.worker.do_work) # when thread starts, start worker
        self.thread.finished.connect(self.worker.stop) # when thread finishes, stop worker

        # Start Button action:
        self.btn_start.clicked.connect(self.thread.start)

        # Stop Button action:
        self.btn_stop.clicked.connect(self.stop_thread)

        self.show()

    # When stop_btn is clicked this runs. Terminates the worker and the thread.
    def stop_thread(self):
        print("It should stop printing numbers now and not crash")
        self.worker.disconnect()
        self.thread.terminate()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    gui = Gui()
    sys.exit(app.exec_())

编辑:虽然MalloyDelacroix answer 工作了一段时间,但我现在遇到了一个问题:

如果来自Workerdo_work 是一个永远循环的导入函数,我如何通过单击按钮来停止它?我想强制关闭它。

from test import s_main

class Worker(QObject):

    finished = pyqtSignal()  # give worker class a finished signal

    def __init__(self, parent=None):
        QObject.__init__(self, parent=parent)
        self.continue_run = True  # provide a bool run condition for the class

    def do_work(self):

        s_main()

        self.finished.emit()  # emit the finished signal when the loop is done

    def stop(self):
        self.continue_run = False  # set the run condition to false on stop

test.py:

def s_main():
    i = 1
    while True:
        i = i + 1
        print(i)

【问题讨论】:

    标签: python pyqt5


    【解决方案1】:

    以下是您发布的代码的工作示例。我已经在我更改的区域制作了 cmets,并解释了原因。

    import sys
    from PyQt5.QtWidgets import (QWidget,
                             QPushButton, QApplication, QGridLayout)
    from PyQt5.QtCore import QThread, QObject, pyqtSignal
    
    
    class Worker(QObject):
    
        finished = pyqtSignal()  # give worker class a finished signal
    
        def __init__(self, parent=None):
            QObject.__init__(self, parent=parent)
            self.continue_run = True  # provide a bool run condition for the class
    
        def do_work(self):
            i = 1
            while self.continue_run:  # give the loop a stoppable condition
                print(i)
                QThread.sleep(1)
                i = i + 1
            self.finished.emit()  # emit the finished signal when the loop is done
    
        def stop(self):
            self.continue_run = False  # set the run condition to false on stop
    
    
    class Gui(QWidget):
    
        stop_signal = pyqtSignal()  # make a stop signal to communicate with the worker in another thread
    
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
    
            # Buttons:
            self.btn_start = QPushButton('Start')
            self.btn_start.resize(self.btn_start.sizeHint())
            self.btn_start.move(50, 50)
            self.btn_stop = QPushButton('Stop')
            self.btn_stop.resize(self.btn_stop.sizeHint())
            self.btn_stop.move(150, 50)
    
            # GUI title, size, etc...
            self.setGeometry(300, 300, 300, 220)
            self.setWindowTitle('ThreadTest')
            self.layout = QGridLayout()
            self.layout.addWidget(self.btn_start, 0, 0)
            self.layout.addWidget(self.btn_stop, 0, 50)
            self.setLayout(self.layout)
    
            # Thread:
            self.thread = QThread()
            self.worker = Worker()
            self.stop_signal.connect(self.worker.stop)  # connect stop signal to worker stop method
            self.worker.moveToThread(self.thread)
    
            self.worker.finished.connect(self.thread.quit)  # connect the workers finished signal to stop thread
            self.worker.finished.connect(self.worker.deleteLater)  # connect the workers finished signal to clean up worker
            self.thread.finished.connect(self.thread.deleteLater)  # connect threads finished signal to clean up thread
    
            self.thread.started.connect(self.worker.do_work)
            self.thread.finished.connect(self.worker.stop)
    
            # Start Button action:
            self.btn_start.clicked.connect(self.thread.start)
    
            # Stop Button action:
            self.btn_stop.clicked.connect(self.stop_thread)
    
            self.show()
    
        # When stop_btn is clicked this runs. Terminates the worker and the thread.
        def stop_thread(self):
            self.stop_signal.emit()  # emit the finished signal on stop
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        gui = Gui()
        sys.exit(app.exec_())
    

    编辑:

    答案还是基本一样,只需要将停止按钮连接到其他方法的运行条件即可。

    test.py

    import time
    
    run = True
    
    def s_main():
        x = 1
        while run:
            print(x)
            x += 1
            time.sleep(1)
    

    worker.py

    import test
    
    class Worker(QObject):
    
        finished = pyqtSignal()  # give worker class a finished signal
    
        def __init__(self, parent=None):
            QObject.__init__(self, parent=parent)
    
        def do_work(self):
    
            s_main()
    
            self.finished.emit()  # emit the finished signal when the loop is done
    
        def stop(self):
            test.run = False  # set the run condition to false on stop    
    

    【讨论】:

    • 非常感谢!我结束了将 Thread 和 Worker 创建代码移动到一个函数(就像我对 stop_thread 函数所做的那样),所以我可以一遍又一遍地停止和重新启动进程。
    • 你好,我遇到了一个意想不到的问题,你能看到我更新的问题(“编辑”部分)吗?
    • 我已经编辑了我的答案以解决您的更新问题。将来,这类问题可能更适合新问题,而不是编辑已回答的旧问题。
    猜你喜欢
    • 2019-06-09
    • 2021-05-29
    • 2016-08-27
    • 1970-01-01
    • 2011-08-27
    • 1970-01-01
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多