S
S
Spheniscus2017-11-07 09:41:43
Python
Spheniscus, 2017-11-07 09:41:43

Why does the GUI freeze?

I am writing a program in pyqt5 + qml.
By the button I carry out calculations and it is necessary to display the progress of the calculation.
The progress is displayed in the console perfectly, but the gui hangs for the duration of the calculation and comes to life only after execution and writes the status "done".
I tried to do calculations in one thread, and draw gui in another - the result remains unchanged
How to make the gui not hang during the calculation?

#!/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()

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
Sergey Gornostaev, 2017-11-07
@Spheniscus

Use 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_())

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question