在pyqt5中退出GUI时终止正在运行的进程的正确方法是什么?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在pyqt5中退出GUI时终止正在运行的进程的正确方法是什么?相关的知识,希望对你有一定的参考价值。
当我单击qbtn按钮退出GUI时,GUI消失了,但是convert(filename)
中的过程继续在后台运行。
我如何做到这一点,以便当用户按下退出按钮时,GUI消失并且正在运行的进程终止?
我正在使用pyqt5 GUI(如下):
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPixmap, QFont, QColor, QIcon
from PyQt5 import QtCore
from PyQt5 import QtGui
import sys
from pathlib import Path
import threading, queue, time
file_queue = queue.Queue()
def get_logo_path():
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = Path(sys._MEIPASS).joinpath('files').absolute()
except Exception:
base_path = Path(".").absolute()
logo_path = base_path.joinpath('pi_logo.png')
return str(logo_path.absolute())
class WorkerThread(QtCore.QRunnable):
__keep_alive = True
def __init__(self):
super().__init__()
self.queue = queue.Queue()
def addJob(self,filepath):
# Puts an item into the queue; if the queue is full, wait until a free slot is available before adding the item.
self.queue.put(filepath)
def run(self):
while self.__keep_alive:
# Remove and return an item from the queue. If queue is empty, wait until an item is available.
convert(self.queue.get())
def kill(self):
self.__keep_alive = False
# Calls the function that puts item into the queue
self.addJob('')
print("que: ", self.queue)
def convert(filename):
#: main
if filename == '':
print("CONVERT() run when filename == ''")
#return
else:
print("filename", filename)
i2 = 1
while i2 > 0 and i2 < 2500000:
print("Hello, running process convert() (", str(i2), ")")
i2 = i2 + 1
class TitleBar(QHBoxLayout):
__layout = None
def __init__(self):
super().__init__()
label = QLabel()
pixmap = QPixmap(get_logo_path())
label.setPixmap(pixmap)
label.setStyleSheet("QLabel background-color: #646464;")
self.addWidget(label)
qbtn = QPushButton('X')
qbtn.setFont(QFont("Arial", weight=QFont.Bold))
qbtn.setStyleSheet("QPushButton background-color: #641010; color: #FFFFFF;")
qbtn.setMaximumWidth(25)
# Calls quit() when the ex button is clicked
qbtn.clicked.connect(self.close_window)
self.setContentsMargins(10, 10, 10, 10)
self.addWidget(qbtn)
def close_window(self):
print('DEF CLOSE_WINDOW(SELF): QUITTING GUI ONLY!!!!')
app = QApplication.instance()
for widget in app.topLevelWidgets():
print("widget: ", widget)
if isinstance(widget, QMainWindow):
# Closes the window
widget.close()
class BodyLayout(QHBoxLayout):
__navigation = None
__body = None
def __init__(self):
super().__init__()
label = QLabel(
'Drag and drop any directory into the window to begin conversion.'
)
label.setStyleSheet(
"QLabel background-color: #646464; color: #FFFFFF;")
label.setAlignment(QtCore.Qt.AlignCenter)
self.addWidget(label)
class MainWidget(QWidget):
__layout = None
__titlebar = None
__body = None
def __init__(self):
super().__init__()
self.__titlebar = TitleBar()
self.__body = BodyLayout()
self.__layout = QVBoxLayout()
self.__layout.setContentsMargins(0, 0, 0, 0)
self.__layout.addLayout(self.__titlebar, 1)
self.__layout.addLayout(self.__body, 10)
self.setLayout(self.__layout)
class MainWindow(QMainWindow):
__window = None
oldPos = None
oldY = None
oldX = None
workerThread = None
threadPool = None
def __init__(self):
super().__init__()
self.__window = MainWidget()
self.setCentralWidget(self.__window)
sizeObject = QDesktopWidget().screenGeometry(-1)
self.setFixedSize(min(600, sizeObject.width()),
min(150, sizeObject.height()))
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setStyleSheet("QMainWindow background: #646464; ")
self.setAcceptDrops(True)
self.workerThread = WorkerThread()
self.threadPool = QtCore.QThreadPool()
self.threadPool.start(self.workerThread)
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
event.ignore()
def dropEvent(self, event):
for url in event.mimeData().urls():
filepath = Path(url.toLocalFile())
#if filepath.name.endswith('.xlsx'):
if filepath.is_dir():
self.workerThread.addJob(filepath)
def mousePressEvent(self, event):
self.oldPos = event.globalPos()
if self.size().height() + self.pos().y() - self.oldPos.y() < 15:
self.oldY = event.globalPos()
else:
self.oldY = None
if self.size().width() + self.pos().x() - self.oldPos.x() < 15:
self.oldX = event.globalPos()
else:
self.oldX = None
if self.oldPos.y() - self.pos().y() > 60:
self.oldPos = None
def mouseReleaseEvent(self, event):
self.oldPos = None
self.oldY = None
self.oldX = None
def mouseMoveEvent(self, event):
if self.oldPos != None:
delta = QtCore.QPoint(event.globalPos() - self.oldPos)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = event.globalPos()
if self.oldY != None:
delta = QtCore.QPoint(event.globalPos() - self.oldY)
self.setFixedHeight(self.size().height() + delta.y())
self.oldY = event.globalPos()
if self.oldX != None:
delta = QtCore.QPoint(event.globalPos() - self.oldX)
self.setFixedWidth(self.size().width() + delta.x())
self.oldX = event.globalPos()
def closeEvent(self,event):
print('DEF CLOSEEVENT() kills workerThread')
self.workerThread.kill()
#self.quit()
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
答案
线程继续,因为直到convert
从其while循环返回之前,它才能够处理队列。
如果您还想“杀死”它,则必须在每个while循环中不断检查quit条件。
一种简单的解决方案是直接在convert
功能内移动run()
功能。 BUT ...请注意,“终止”不会立即发生,因为某些预定的过程仍将发生(在这种情况下,是打印),这实际上是很好的,因为没有好的杀死进程的方法-出于种种原因,这很好,我在这里不做解释。
def run(self):
while self.__keep_alive:
filename = self.queue.get()
if filename == '':
print("CONVERT() run when filename == ''")
break
#return
else:
print("filename", filename)
i2 = 1
while i2 > 0 and i2 < 2500000:
try:
# a non blocking get that constantly checks the queue
result = self.queue.get(False)
if result == '':
break
except:
pass
print("Hello, running process convert() (", str(i2), ")")
i2 = i2 + 1
else:
continue
break
当然,这是一个非常基本的实现,您可能想要为转换就位时可能发生的任何其他排队创建某种延迟队列(其表现为请求“缓冲区”),以便您以后可以处理它,但这不是此问题的范围。
以上是关于在pyqt5中退出GUI时终止正在运行的进程的正确方法是什么?的主要内容,如果未能解决你的问题,请参考以下文章
Linux_进程终止(进程退出,进程等待(阻塞与非阻塞等待))
在不终止启动 Python 脚本的情况下关闭 pyqt5 GUI