создание нескольких программ windows pyqt5 с потоковой передачей - PullRequest
0 голосов
/ 04 августа 2020

Я пытался сделать самообновляющуюся программу с pyqt5, поэтому подумал, что было бы здорово

показать окно загрузки, пока идет обновление.

Я следил за this ответ, и все было хорошо, пока я не добавил поток, который обновляет программу.

вот мой код.

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from packaging import version
import os
import sys
import time
import threading

updateFlag = False
updateDoneFlag = False

CUR_VERSION = "1.0.1"
LATEST_VERSION = "1.0.2"

class MainWidget(QWidget):
    def __init__(self, parent=None):
        super(MainWidget, self).__init__(parent)
        try:
            self.qle_id = QLineEdit(self)
            self.qle_id.setPlaceholderText("ID")
            self.qle_id.setFocus()
            self.qle_pw = QLineEdit(self)
            self.qle_pw.setPlaceholderText("PW")

            vbox = QVBoxLayout()
            vbox.addStretch(1)
            vbox.addWidget(self.qle_id)
            vbox.addWidget(self.qle_pw)
            vbox.addStretch(1)

            hbox = QHBoxLayout()
            hbox.addStretch(1)
            hbox.addLayout(vbox)
            hbox.addStretch(1)
            self.setLayout(hbox)

        except Exception as e:
            print(e)
            pass

class UpdateWidget(QWidget):
    def __init__(self, parent=None):
        super(UpdateWidget, self).__init__(parent)
        self.gif = QMovie("loading.gif", QByteArray(), self)
        self.loading = QLabel()
        self.loading.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.loading.setAlignment(Qt.AlignCenter)
        self.lbl = QLabel("Update in progress...")
        self.lbl.setAlignment(Qt.AlignCenter)
        self.btn = QPushButton("Cancel", self)

        vbox = QVBoxLayout()
        vbox.addStretch(1)
        vbox.addWidget(self.loading)
        vbox.addWidget(self.lbl)
        vbox.addWidget(self.btn)
        vbox.addStretch(1)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addLayout(vbox)
        hbox.addStretch(1)
        self.setLayout(hbox)

        self.gif.setCacheMode(QMovie.CacheAll)
        self.loading.setMovie(self.gif)
        self.gif.start()
        self.gif.loopCount()
    
        self.updateThr = (threading.Thread(target=self.startUpdate)).start()

    def startUpdate(self):
        global updateFlag, updateDoneFlag
        try:
            while True:
                time.sleep(5)
                if not updateFlag:
                    updateDoneFlag = True
                    break
                time.sleep(5)
                if not updateFlag:
                    updateDoneFlag = True
                    break
                time.sleep(5)
                if not updateFlag:
                    updateDoneFlag = True
                    break
                time.sleep(5)
                updateDoneFlag = True
                global CUR_VERSION
                CUR_VERSION = "1.0.2"
                break
        except Exception as e:
            print(e)
            pass

class WindowManager(QMainWindow):
    def  __init__(self, parent=None):
        super(WindowManager, self).__init__(parent)
        infoMenu = QAction("&Info", self)
        infoMenu.setShortcut("Ctrl+I")
        infoMenu.triggered.connect(self.showProgInfo)
        infoMenu.setStatusTip("About the program")
        updateMenu = QAction("&Update", self)
        updateMenu.setShortcut("Ctrl+T")
        updateMenu.setStatusTip("Check for update")
        updateMenu.triggered.connect(self.checkUpdate)
        exitMenu = QAction("&Exit", self)
        exitMenu.setShortcut("Ctrl+Q")
        exitMenu.setStatusTip("Exit program")
        exitMenu.triggered.connect(self.closeEventForShortcut)

        self.menu = self.menuBar()
        fileMenu = self.menu.addMenu("&Menu")
        fileMenu.addAction(infoMenu)
        fileMenu.addAction(updateMenu)
        fileMenu.addAction(exitMenu)

        self.checkUpdate()
    
    def showMainWindow(self):
        try:
            self.mainWindow = MainWidget(self)
            self.menu.setVisible(True)
            self.setWindowFlag(Qt.WindowCloseButtonHint, True)
            self.setFixedSize(600, 400)
            self.setWindowTitle("Main")
            self.setCentralWidget(self.mainWindow)
            self.show()
        except Exception as e:
            print(e)
            pass
    
    def showUpdateWindow(self):
        global updateFlag
        try:
            updateFlag = True
            self.updateWindow = UpdateWidget(self)
            self.menu.setVisible(False)
            self.setWindowFlag(Qt.WindowCloseButtonHint, False)
            self.setFixedSize(500, 500)
            self.setWindowTitle("Update")
            self.setCentralWidget(self.updateWindow)
            self.updateWindow.btn.clicked.connect(self.cancelUpdate)
            self.show()
        except Exception as e:
            print(e)
            pass
    
    def checkUpdate(self):
        global CUR_VERSION, LATEST_VERSION, updateFlag, updateDoneFlag
        try:
            msg = QMessageBox()
            if version.parse(CUR_VERSION) < version.parse(LATEST_VERSION):
                msg.setWindowTitle("Update alert")
                msg.setText("Update is available (%s to %s)" % (CUR_VERSION, LATEST_VERSION))
                msg.addButton(QPushButton("&Update"), QMessageBox.YesRole)
                msg.setStandardButtons(QMessageBox.Cancel)
                update = msg.exec_()
                if update == QMessageBox.Cancel:
                    self.showMainWindow()
                else:
                    updateFlag = True
                    updateDoneFlag = False
                    self.showUpdateWindow()
        except Exception as e:
            print(e)
            pass
    
    def cancelUpdate(self):
        try:
            self.updateWindow.lbl.setText("Cancelling update...")
            global updateFlag
            updateFlag = False
            self.updateDoneThr = (threading.Thread(target=self.waitUntilUpdateThrDie)).start()
        except Exception as e:
            print(e)
            pass
    
    def waitUntilUpdateThrDie(self):
        global updateDoneFlag
        try:
            while True:
                if updateDoneFlag:
                    self.showMainWindow()
                    break
        except Exception as e:
            print(e)
            pass
    
    def showProgInfo(self):
        infoBox = QMessageBox()
        infoBox.information(self, "Information", "Hey what's up guys it's scarce here")

    def closeEvent(self, event):
        global exitFlag, updateFlag
        if not updateFlag:
            close = QMessageBox.question(self, "Exit", "Exit the program?", QMessageBox.Yes | QMessageBox.No)
            if close == QMessageBox.Yes:
                exitFlag = True
                updateFlag = False
                event.accept()
            else:
                event.ignore()
        else:
            close = QMessageBox.question(self, "Update", "Cancel the update?", QMessageBox.Yes | QMessageBox.No)
            if close == QMessageBox.Yes:
                self.cancelUpdate()
                event.ignore()
            else:
                event.ignore()

    def closeEventForShortcut(self):
        close = QMessageBox.question(self, "Exit", "Exit the program?", QMessageBox.Yes | QMessageBox.No)
        if close == QMessageBox.Yes:
            global exitFlag, updateFlag
            exitFlag = True
            updateFlag = False
            QCoreApplication.instance().quit()
        else:
            pass

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = WindowManager()
    sys.exit(app.exec_())

После того, как обновление было отменено или завершено, вместо этого появилось это сообщение об ошибке главного окна.

QObject::setParent: Cannot set parent, new parent is in a different thread
QObject::setParent: Cannot set parent, new parent is in a different thread
QObject::setParent: Cannot set parent, new parent is in a different thread

Я погуглил, и он сказал, что я пытался изменить GUI из другого потока.

Но разве не все GUI изменились в классе WindowManager? Классы QWidget просто меняют флаги.

Итак, класс WindowManager знает, что он должен отображать.

Я действительно сбиваю с толку .. Будет здорово, если вы скажете мне, что я делаю неправильно .

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