简体   繁体   中英

Run a while loop in pyQt5 using QThread, assigning true and false on stop buttons

I got a project that listens to the microphone if I ever press start. I am so new to pyqt5 so I don't really know Qthreading that much, plus most of the examples are progress bars and for loops. I want that when it presses start it runs the while loop of recording audio for 10 seconds, identifying it, and doing again. And that it only stops when I press stop, a variable is now False. Now this is what I came up with. I am sorry if it looks dumb because I don't really know that much from Qthread. I just want to be able to run this one in particular.

class AvisoWindow(QtWidgets.QMainWindow, Aviso_Main.Ui_MainWindow):
    def __init__(self, parent=None):
        super(AvisoWindow, self).__init__(parent)
        self.setupUi(self)
        self.is_Played = True
        self.start_btn.clicked.connect(self.startClicked)
        self.stop_btn.clicked.connect(self.stopClicked)

    def startClicked(self):
        while self.is_Played == True:
            listen()
            time.sleep(0.01)

    def stopClicked(self):
        self.is_Played = False
        self.finished.emit()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = AvisoWindow()
    threading.Thread(target=form.__init__(), daemon=True).start()
    form.show()
    app.exec_()

First of all, nothing related to the UI shall ever be run or accessed in an external thread. Blocking functions and while loops (unless it's guaranteed that they exit almost instantly) should also be avoided, as they block the event loop preventing proper redrawing of the UI and user interaction.

Even assuming that directly using threads with UI was possible, your attempt has two important problems:

  1. __init__() should never be called externally (and, even in that case, it expects at least the instance as argument);
  2. the target argument of Thread expects a callable (a reference to a function), but you're already calling the method (using the parentheses), so it would use the returned value of that called function (which is usually None for an init);

In order to use threads that have to react to an UI environment, in Qt you should create a subclass of QThread that acts as your "worker".

class Worker(QThread):
    result = pyqtSignal(str)
    def run(self):
        self.keepRunning = True
        while self.keepRunning:
            res = someFunctionThatReturnsAString()
            self.result.emit(res)
            time.sleep(0.01)

    def stop(self):
        self.keepRunning = False


class AvisoWindow(QtWidgets.QMainWindow, Aviso_Main.Ui_MainWindow):
    def __init__(self, parent=None):
        super(AvisoWindow, self).__init__(parent)
        self.setupUi(self)
        self.worker = Worker()
        self.worker.result.connect(self.resultReceived)
        self.start_btn.clicked.connect(self.startClicked)
        self.stop_btn.clicked.connect(self.stopClicked)

    def startClicked(self):
        if not self.worker.isRunning():
            self.worker.start()

    def stopClicked(self):
        self.worker.stop()

    def resultReceived(self, result):
        print(result)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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