Stopping Main Gui and worker thread before completion for PyQt5
-
Hello. Recently started using PyQt5 and still learning.
The code works. Here is the background and outline of the code:
OS: Ubuntu Linux 18.04, bash shell
Steps:
- Start the gui from the command line
- Gui pops up
- Press 'Start' button to begin execution of two *.py scripts.
- Based on examples online, created a worker QObject so the gui would not freeze while the long running loop continues.
You can see the gui here:
When pressing the STOP button, I want add the ability closing everything before completion if necessary: Closing the gui window, shutting down the ongoing processes created by the Worker thread. The equivalent of pressing Ctrl + c on the keyboard.
Having a hard to time figuring it out. Any suggestions would help.
Thanks.
d.
import sys import os from time import sleep import signal from PyQt5.QtCore import Qt from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtWidgets import ( QApplication, QLabel, QMainWindow, QPushButton, QVBoxLayout,QProgressBar, QWidget, ) from PyQt5.QtCore import QObject, QThread, pyqtSignal # Snip... # Step 1: Create a worker class class Worker(QObject): finished = pyqtSignal() progress = pyqtSignal(int) def run(self): """Long-running task.""" for i in range(5): #sleep(1) os.system("./test_code01.py") self.progress.emit(i + 1) self.finished.emit() class Window(QMainWindow): signal.signal(signal.SIGINT,signal.SIG_DFL) def __init__(self, parent=None): super().__init__(parent) self.progress_window() def progress_window(self): self.pbar_window=QWidget() self.pbar_window.setWindowTitle("QT Progressbar Example") self.pbar_window.setGeometry(432,232,320,200) self.pbar = QProgressBar(parent=self.pbar_window) self.pbar.setGeometry(50, 74, 200, 25) self.pbar.setValue(0) self.pbar_start_push = QtWidgets.QPushButton('Start',parent=self.pbar_window) self.pbar_start_push.setGeometry(50, 114, 55, 25) self.pbar_start_push.setEnabled(True) self.pbar_stop_push = QtWidgets.QPushButton('STOP',parent=self.pbar_window) self.pbar_stop_push.setGeometry(145, 114, 55, 25) self.pbar_window.show() self.pbar_start_push.clicked.connect(self.start_push) self.pbar_stop_push.clicked.connect(self.stopped_push) def start_push(self): print("started") self.pbar_start_push.setEnabled(False) self.runLongTask() def stopped_push(self): print("stopped") #print(self.thread.isRunning()) self.thread.exit() #print(self.thread.isRunning()) def reportProgress(self, n): self.stepLabel.setText(f"Long-Running Step: {n}") # Snip... def runLongTask(self): # Step 2: Create a QThread object self.thread = QThread() # Step 3: Create a worker object self.worker = Worker() # Step 4: Move worker to the thread self.worker.moveToThread(self.thread) # Step 5: Connect signals and slots self.thread.started.connect(self.worker.run) self.worker.finished.connect(self.thread.quit) self.worker.finished.connect(self.worker.deleteLater) self.thread.finished.connect(self.thread.deleteLater) self.worker.progress.connect(self.reportProgress) # Step 6: Start the thread self.thread.start() app = QApplication(sys.argv) win = Window() #win.show() sys.exit(app.exec_())
test_code01.py
#!/usr/bin/python3 import os i = 0 while i < 100000000000000: i+=1 os.system("./second_test_code02.py")
second_test_code02.py
#!/usr/bin/python3 import os i = 0 while i < 1000000000000000: i+=1
-
Hi and welcome to devnet,
The cleanest way to do that is to design your long lasting operation so that they can be interrupted. That way you can raise a flag at any point in time and get them to stop more or less quickly depending on the size of the step they are currently executing.
-
@SGaist said in Stopping Main Gui and worker thread before completion for PyQt5:
Hi and welcome to devnet,
Thank you for the welcoming. :
The cleanest way to do that is to design your long lasting operation so that they can be interrupted. That way you can raise a flag at any point in time and get them to stop more or less quickly depending on the size of the step they are currently executing.
I think that is my dilemma. Are flags only raised/checked after each iteration of a for/while loop? Given the size of the step can take about 5 minutes, are you saying I would have to wait 5 minutes before shutting down the long task with a flag/check? My hope is to stop the long task at any point in time by clicking the STOP pushbutton, like you can with a ctrl+c from a keyboard.
d.
-
That completely depends on how you implement your operation. You can check the flag at each iteration, after each single step of the operation, etc. It's up to you to find the right balance.
-
Did compile(pyinstaller.py) the module including Thread inside
as nonwindowed executable,
ran ???.exe (logging into log-file),
in QtWindow app read log
and ( addItems) into QListWidget frame. -
Did compile(pyinstaller.py) the module including Thread inside
as nonwindowed executable,
ran ???.exe (logging into log-file),
in QtWindow app read log
and ( addItems) into QListWidget frame.@reine said in Stopping Main Gui and worker thread before completion for PyQt5:
Did compile(pyinstaller.py) the module including Thread inside
as nonwindowed executable,
ran ???.exe (logging into log-file),
in QtWindow app read log
and ( addItems) into QListWidget frame.Hi,
How is that related to this thread ?
-
That completely depends on how you implement your operation. You can check the flag at each iteration, after each single step of the operation, etc. It's up to you to find the right balance.
@SGaist said in Stopping Main Gui and worker thread before completion for PyQt5:
That completely depends on how you implement your operation. You can check the flag at each iteration, after each single step of the operation, etc. It's up to you to find the right balance.
Thanks for your suggestions. I decided to convert the two scripts called in the Worker class into two functions of the Worker class instead.That made things much cleaner and easier to shut things down when necessary because it is viewed as one process, with one process ID.
Thanks for helping me see things from a different point of view.
d.
-
You're welcome !
Since you have it working now, please mark the thread as solved using the "Topic Tools" button or the three dotted menu beside the answer you deem correct so that other forum users may know a solution has been found :-)