PyQt thread thread support? QThread and QObject

After reading and searching, I try to use the QObject generator, and then use the movetoThread method to start an independent process and allow QMainWindow to continue to respond. This did not work when I tried to perform the operation in the QThread.run () method. The following code is my attempt to make a simple example. Although the code runs in a thread independent of MainWindow, it does not interrupt. The only way to stop the thread is to set employee.end = True. Which, I think, should not be a way to do this.

"""
This is a program to test Threading with Objects in PyQt4.
"""

from time import sleep
import sys

from PyQt4.QtCore import QObject, pyqtSlot, pyqtSignal, QThread
from PyQt4.QtGui import QMainWindow, QApplication, QProgressBar
from PyQt4.QtGui import QPushButton, QVBoxLayout, QWidget

class workerObject(QObject):
    bar_signal = pyqtSignal(int)
    res_signal = pyqtSignal(str)
    term_signal = pyqtSignal()

    def __init__(self, maxIters):
        super(workerObject, self).__init__()
        self.maxIters = maxIters

    def run(self):
        self.bar_signal.emit(self.maxIters)        
        sleep(1)
        self.end = False

        for step in range(self.maxIters):
            if self.end:
                self.maxIters = step
                break
            self.bar_signal.emit(step)
            sleep(2)

        self.res_signal.emit("Got to {}".format(self.maxIters)) 
        self.term_signal.emit()

    @pyqtSlot()
    def mystop(self):
        print "stop signalled?"
        self.end = True

class MCwindow(QMainWindow):
    abort_signal = pyqtSignal(name='abort_signal')

    def __init__(self):
        super(MCwindow,self).__init__()        
        self.maxIters = 50

        widget = QWidget()
        layout = QVBoxLayout(widget)
        self.go_btn = QPushButton()
        self.go_btn.setText('Go')
        layout.addWidget(self.go_btn)
        self.abort_btn = QPushButton()
        self.abort_btn.setText('Stop')
        layout.addWidget(self.abort_btn)
        self.simulation_bar = QProgressBar()
        self.simulation_bar.setRange(0, self.maxIters)
        self.simulation_bar.setFormat("%v")
        layout.addWidget(self.simulation_bar)
        self.setCentralWidget(widget)

        self.go_btn.clicked.connect(self.run_mc)
        # The button calls the windows method to stop --- it could 
        # be that is 'clicked' calls the worker.mystop
#        self.abort_btn.clicked.connect(self.stop_mc)
        # This allows for the abort button to do somethign in the MainWindow
        # before the abort_signal is sent, this works
        self.abort_btn.clicked.connect(self.stop_mc)

    def run_mc(self):        
        self.thread = QThread()                
        self.worker = workerObject(self.maxIters)
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run)
        # This is the simple stop method, but does not work
#        self.abort_btn.clicked.connect(self.worker.mystop)
        # This uses the signal in the MCwindow - this connection does NOT works
        self.abort_signal.connect(self.worker.mystop)
        # This does NOT stop the thread
        # and would not allow for any clean up in the worker.
#        self.abort_signal.connect(self.thread.terminate)
        # This is a 'bad' way to stop the woker ... It does, however, work
#        self.abort_signal.connect(self.stopper)
        self.worker.bar_signal.connect(self.setBar)
        self.worker.res_signal.connect(self.setData)
        self.worker.term_signal.connect(self.thread.terminate)
        self.thread.start()

    def stop_mc(self):
        print "Stopping?!"
        # This signal is NEVER seen by the Worker.
        self.abort_signal.emit()

    def stopper(self):
        print "I should stop?!"
        # Should use signals to tell the worker to stop - and not setting a attribute
        self.worker.end=True

    @pyqtSlot(int)
    def setBar(self, val):
        self.simulation_bar.setValue(val)

    @pyqtSlot(str)    
    def setData(self, txt):
        print "Got done Sig!", txt

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MCwindow()
    window.show()
    sys.exit(app.exec_())
+4
source share
2 answers

, , abort_signal, , , , . , - , .

- , . start() -, abort_signal . , run() for loop, , gui!

, , :

class MCwindow(QMainWindow):
    abort_signal = pyqtSignal(name='abort_signal')

    def __init__(self):
        super(MCwindow,self).__init__()
        # use a sane default
        self.maxIters = 5
        ...
        # DO NOT use QThread.terminate
        self.worker.term_signal.connect(self.thread.quit)

, "", "" . :

Stopping?!
Got done Sig! Got to 5
stop signalled?

, "stop signaled" , run() . , , . :

     for step in range(self.maxIters):
        QApplication.processEvents()
        ...

:

Stopping?!
stop signalled?
Got done Sig! Got to 2

, , .

+4

, . python - join.

PyQt join quit, terminate. , True.

0

Source: https://habr.com/ru/post/1611476/


All Articles