I want to cancel the process ran by the subprocess.Popen.
This code is for the explanation.
test_ui.py
import sys
from PyQt5.QtWidgets import (
QApplication,
QWidget,
QHBoxLayout,
QVBoxLayout,
QPushButton,
QTextEdit,
)
from test_worker import TestWorker
class TestUI(QWidget):
def __init__(self):
super().__init__()
self.worker = TestWorker()
self.worker.outSignal.connect(self.logging)
self.result = QTextEdit()
self.init_ui()
def init_ui(self):
start_button = QPushButton("Start")
start_button.clicked.connect(self.start)
cancel_button = QPushButton("Cancel")
cancel_button.clicked.connect(self.cancel)
hlayout = QHBoxLayout()
hlayout.addWidget(start_button)
hlayout.addWidget(cancel_button)
vlayout = QVBoxLayout()
vlayout.addLayout(hlayout)
vlayout.addWidget(self.result)
self.setLayout(vlayout)
self.show()
def start(self):
self.result.clear()
self.worker.run_command(["ping stackoverflow.com -n 30"])
def cancel(self):
self.worker.cancel_command()
def logging(self, msg):
msg = msg.strip()
if msg != "":
self.result.append(msg)
if __name__ == "__main__":
APP = QApplication(sys.argv)
ex = TestUI()
sys.exit(APP.exec_())
test_worker.py
import os
import signal
import threading
import subprocess
from PyQt5.QtCore import QObject, pyqtSignal
class TestWorker(QObject):
outSignal = pyqtSignal(str)
def __init__(self):
super().__init__()
def run_command(self, cmd):
threading.Thread(target=self._execute_command, args=(cmd), daemon=True).start()
def cancel_command(self):
# self.proc.kill()
# os.kill(self.proc.pid, signal.SIGTERM)
def _execute_command(self, cmd):
self.proc = subprocess.Popen(
cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
shell=True,
universal_newlines=True,
)
for line in self.proc.stdout:
self.outSignal.emit(line)
self.proc.kill()
=> It doesn't work. But "shell=True" is needed.
os.kill(self.proc.pid, signal.SIGTERM)
=> It doesn't work as well. And if I press the cancel button twice, I get an error.
"FileNotFoundError: [WinError 2] The system cannot find the file specified"
Please help me with this problem.
You have to use a flag to indicate that the process should be canceled, then kill the process and finish the thread execution. A threading.Event
could be used for this case.
class TestWorker(QObject):
outSignal = pyqtSignal(str)
def __init__(self):
super().__init__()
self.stop_event = threading.Event()
def run_command(self, cmd):
self.stop_event.clear()
threading.Thread(target=self._execute_command, args=(cmd), daemon=True).start()
def cancel_command(self):
self.stop_event.set()
def _execute_command(self, cmd):
if self.stop_event.isSet():
return
proc = subprocess.Popen(
cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
shell=True,
universal_newlines=True,
)
if self.stop_event.isSet():
proc.kill()
return
for line in proc.stdout:
if self.stop_event.isSet():
proc.kill()
return
self.outSignal.emit(line)
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.