Reputation: 59
When I click the qbtn button to quit the GUI, the GUI goes away, but the process in convert(filename)
continues running in the background.
How can I make it so that when a user presses the exit button, the GUI disappears and any running process terminates?
I am using pyqt5 GUI (below):
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_())
Upvotes: 0
Views: 248
Reputation: 48231
The thread continues because it will not be able to process the queue until convert
returns from its while loop.
If you want to also be able to "kill" that, you'll have to constantly check the quit condition at each while loop.
A simple solution is to move the convert
function directly within the run()
function. BUT... note that the "killing" won't happen immediately, as some already scheduled process is still going to happen (in this case, the printing), and this is actually good, as there's no nice way to kill a process - and that's good for a moltitude of reason I won't explain here.
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
Of course this is a very basic implementation, you might probably want to create some sort of delayed queue (that behaves as a request "buffer") for any other queueing that might happen while the conversion is in place, so that you can process it later, but that's not the scope of this question.
Upvotes: 1