I'm making a PyQt app that allows users to select a script file from their machine, the app then executes it using exec()
on a separate QThread
then shows them the results. I've already implemented all that, and now I'm trying to add a "Stop Executing" button.
I'm not able to interrupt the script execution, which should happen whenever the user presses the "Stop Executing" button. I can't stop the QObject
's task that's executing the script or terminate the QThread
that's hosting the object.
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import QObject, QThread
class Execute(QObject):
def __init__(self, script):
super().__init__()
self.script = script
def run(self):
exec(open(self.script).read())
class GUI(QMainWindow):
# Lots of irrelevant code here ...
# Called when "Start Executing" button is pressed
def startExecuting(self, user_script):
self.thread = QThread()
self.test = Execute(user_script)
self.test.moveToThread(self.thread)
self.thread.started.connect(self.test.run)
self.thread.start()
# Called when "Stop Executing" button is pressed
def stopExecuting(self):
# Somehow stop script execution
There's a ton of question related to stopping an exec()
or a QThread
, but none of them work in my case. Here's what I've tried:
thread.quit()
from GUI (kills thread after script execution ends - same with wait()
) SystemExit
from object (exits the whole app after script execution ends) thread.terminate()
from GUI (app crashes when "Stop Executing" button is pressed) run()
isn't loop based) So, is there any other solution to stop the exec()
or kill the thread right when the button is pressed?
Thank's to @ekhumoro's hint about using multiprocessing instead of multithreading, I was able to find a solution.
I used a QProcess
to execute the script, and then called process.kill()
when the "Stop Executing" button is clicked. Like so:
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import QProcess
class GUI(QMainWindow):
# Lots of irrelevant code here ...
# Called when "Start Executing" button is pressed
def startExecuting(self, user_script):
self.process = QProcess()
self.process.setProcessChannelMode(QProcess.MergedChannels)
self.process.start("python", ["-u", user_script])
# Called when "Stop Executing" button is pressed
def stopExecuting(self):
self.process.kill()
This stops the script execution right away without interrupting the GUI process, which's exactly what I was looking for.
Check next code, maybe it can help you:
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import QObject, QThread
from PyQt5 import Qt #+
class WorkThread(Qt.QThread):
threadSignal = Qt.pyqtSignal(int)
def __init__(self):
super().__init__()
def run(self, *args, **kwargs):
c = 0
while True:
Qt.QThread.msleep(100)
c += 1
self.threadSignal.emit(c)
class MsgBox(Qt.QDialog):
def __init__(self):
super().__init__()
layout = Qt.QVBoxLayout(self)
self.label = Qt.QLabel("")
layout.addWidget(self.label)
close_btn = Qt.QPushButton("Close")
layout.addWidget(close_btn)
close_btn.clicked.connect(self.close)
self.setGeometry(900, 65, 400, 80)
self.setWindowTitle('MsgBox from WorkThread')
class GUI(Qt.QWidget): #(QMainWindow):
def __init__(self):
super().__init__()
layout = Qt.QVBoxLayout(self)
self.btn = Qt.QPushButton("Start thread.")
layout.addWidget(self.btn)
self.btn.clicked.connect(self.startExecuting)
self.msg = MsgBox()
self.thread = None
# Lots of irrelevant code here ...
# Called when "Start/Stop Executing" button is pressed
def startExecuting(self, user_script):
if self.thread is None:
self.thread = WorkThread()
self.thread.threadSignal.connect(self.on_threadSignal)
self.thread.start()
self.btn.setText("Stop thread")
else:
self.thread.terminate()
self.thread = None
self.btn.setText("Start thread")
def on_threadSignal(self, value):
self.msg.label.setText(str(value))
if not self.msg.isVisible():
self.msg.show()
if __name__ == '__main__':
app = Qt.QApplication([])
mw = GUI()
mw.show()
app.exec()
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.