Как правильно завершить работающий процесс при выходе из GUI в pyqt5? - PullRequest
0 голосов
/ 25 марта 2020

Когда я нажимаю кнопку 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_())

1 Ответ

0 голосов
/ 25 марта 2020

Поток продолжается, потому что он не сможет обработать очередь до тех пор, пока convert не вернется из своего времени l oop.

Если вы хотите иметь возможность "убить" это, вы ' Вам придется постоянно проверять состояние quit каждый раз, пока l oop.

Простое решение - переместить функцию convert непосредственно в функцию run(). НО ... обратите внимание, что «убийство» произойдет не сразу, так как какой-то уже запланированный процесс все еще будет происходить (в данном случае, печать), и это на самом деле хорошо, так как нет хороший способ убить процесс - и это хорошо по причине, которую я не буду здесь объяснять.

    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

Конечно, это очень базовая c реализация, вы Возможно, вы захотите создать какую-то задержанную очередь (которая ведет себя как «буфер» запроса) для любой другой очереди, которая может произойти, пока выполняется преобразование, чтобы вы могли обработать ее позже, но это не охват этого вопроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...