@Spheniscus

Почему зависает GUI?

Пишу программу на pyqt5 + qml.
По кнопке провожу вычисления и необходимо выводить прогресс выполнения вычисления.
В консоль прогресс выводится отлично, а вот gui на время вычисления зависает и оживает только после выполнения и пишет статус "готово".

Пробовал вычисления делать в одном потоке, а рисовать gui в другом - результат остается неизменный

Как сделать чтобы gui не зависал при вычислении?

#!/usr/bin/python

import apt
import time
import threading
import mysql.connector
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty
from PyQt5.QtQml import QQmlApplicationEngine

class Application(QObject, apt.progress.base.InstallProgress):
    def __init__(self):
        QObject.__init__(self)
        apt.progress.base.InstallProgress.__init__(self)
        self._pkg = None
        self.progress = 0.
        self.last = 0.0

    progressResult = pyqtSignal(float, arguments=['progress'])

    def start_update(self):
        pass

    def finish_update(self):

        self.last = 100.0
        self.progressResult.emit(self.last)
        print self.last
        print "finish"

    def status_change(self, pkg, percent, status):
        if percent <= 100.0:

            self.last = percent
            self.progressResult.emit(self.last)
            print self.last

    def update_interface(self):
        apt.progress.base.InstallProgress.update_interface(self)
        # usefull to e.g. redraw a GUI
        time.sleep(0.1)

    @pyqtSlot(str)
    def removePackage(self, packName):

        self._c = apt.Cache()
        self._pkg = self._c[packName]

        if self._pkg.is_installed:
            self._pkg.mark_delete(True, True)

        try:
            threading.Thread(target=self._c.commit(install_progress=Application()), daemon=True).start()
        except:
            pass

        self.progressResult.emit(100)
        self._c.close()


def window():
    import sys

    # Create an instance of the application
    app = QGuiApplication(sys.argv)
    # Create QML engine
    engine = QQmlApplicationEngine()
    # Create a calculator object
    application = Application()
    # And register it in the context of QML
    engine.rootContext().setContextProperty("application", application)
    # Load the qml file into the engine
    engine.load("qml/main.qml")

    engine.quit.connect(app.quit)
    sys.exit(app.exec_())

# Main Function
if __name__ == '__main__':
    window()
  • Вопрос задан
  • 1200 просмотров
Решения вопроса 1
sergey-gornostaev
@sergey-gornostaev Куратор тега Python
Седой и строгий
Используйте QThread:
import sys
import time
from PyQt5 import QtCore, QtWidgets

class SlowTask(QtCore.QThread):
    updated = QtCore.pyqtSignal(int)
    running = False

    def __init__(self, *args, **kwargs):
        super(SlowTask, self).__init__(*args, **kwargs)
        self.percent = 0
        self.running = True

    def run(self):
        while self.running:
            self.percent += 1
            self.percent %= 100
            self.updated.emit(int(self.percent))
            time.sleep(0.1)

    def stop(self):
        self.running = False


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setupUi()

    def setupUi(self):
        self.setWindowTitle("Test")
        self.resize(446, 207)

        self.progressbar = QtWidgets.QProgressBar(self)
        self.progressbar.setGeometry(QtCore.QRect(40, 70, 381, 23))
        self.progressbar.setProperty("value", 0)

        self.btn_start = QtWidgets.QPushButton("Start", self)
        self.btn_start.setGeometry(QtCore.QRect(110, 110, 75, 23))
        self.btn_start.setEnabled(True)
        self.btn_start.clicked.connect(self.on_start)

        self.btn_stop = QtWidgets.QPushButton("Stop", self)
        self.btn_stop.setGeometry(QtCore.QRect(260, 110, 75, 23))
        self.btn_stop.setEnabled(False)
        self.btn_stop.clicked.connect(self.on_stop)

    def toggle_buttons(self):
        self.btn_start.setEnabled(not self.btn_start.isEnabled())
        self.btn_stop.setEnabled(not self.btn_stop.isEnabled())

    def on_update(self, data):
        self.progressbar.setValue(data)
#        if data == 99:
#            self.on_stop()

    def on_start(self):
        self.toggle_buttons()
        self.task = SlowTask(self)
        self.task.updated.connect(self.on_update)
        self.task.start()

    def on_stop(self):
        self.task.stop()
        self.progressbar.setValue(0)
        self.toggle_buttons()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы