Moondancer
Moondancer

Reputation: 133

Window showing white

So I want to make a custom window with shows the progress of an action. When I show the window normally without running the function, it shows white for half a second, but that's with every window, and shows then the widgets. But when I show it in the function, the widgets don't show up. Here's the code (it's in a class):

    def compare(self):
        progress = CompareProgress()
        progress.ui.step.setText("Schritt 1/3")
        progress.ui.progressBar1.setMaximum(4)
        progress.ui.progressBar1.setValue(1)
        progress.ui.progressBar2.setValue(0)
        progress.ui.progressBar2.setMaximum(10)
        progress.show()
        with open(self.ui.csv_c_path.text(), "r") as f:
            old = f.readlines()
        with open(self.ui.csv_path.text(), "r") as f:
            new = f.readlines()

        progress.ui.step.setText("Schritt 2/3")
        progress.ui.progressBar1.setValue(2)

        diff = difflib.ndiff(old, new)

        progress.ui.step.setText("Schritt 3/3")
        progress.ui.progressBar1.setValue(3)

        text = ""
        x = 0
        for _, _ in enumerate(diff):
            x += 1

        progress.ui.progressBar2.setMaximum(x)
        # Get differences between old and new csv
        for i, s in enumerate(diff):
            progress.ui.progressBar2.setValue(i)
            if not s[0] == " ":
                text += s

        print(text)

        message.ui.textEdit.setText(text)
        message.show()
        progress.close()

Upvotes: 0

Views: 112

Answers (1)

eyllanesc
eyllanesc

Reputation: 244291

The problem is that you are executing the task that can consume a lot of time in the GUI thread causing it to freeze, instead you must execute it in a new one and update the information through signals:

import difflib
from functools import cached_property
import threading

from PyQt5 import QtCore, QtWidgets


class Worker(QtCore.QObject):
    stepChanged = QtCore.pyqtSignal(int, int)
    progressChanged = QtCore.pyqtSignal(int, int)
    diffTextChanged = QtCore.pyqtSignal(str)

    def start(self, file_a, file_b):
        threading.Thread(
            target=self._execute,
            args=(
                file_a,
                file_b,
            ),
            daemon=True,
        ).start()

    def _execute(self, file_a, file_b):
        diff = None
        self.stepChanged.emit(1, 3)
        with open(file_a, "r") as f1:
            with open(file_b, "r") as f2:
                lines_a = f1.readlines()
                lines_b = f2.readlines()
                self.stepChanged.emit(2, 3)
                diff = difflib.ndiff(lines_a, lines_b)
                self.stepChanged.emit(3, 3)

        if diff is None:
            return

        size = 0
        text = ""

        lines = []
        for size, s in enumerate(diff, start=1):
            lines.append(s)

        self.progressChanged.emit(0, size)
        for i, line in enumerate(lines, start=1):
            self.progressChanged.emit(i, size)
            if not line.startswith(" "):
                text += line
        self.diffTextChanged.emit(text)


class Viewer(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        lay = QtWidgets.QFormLayout(self)
        lay.addRow(self.button)
        lay.addRow("Input1", self.lineedit_a)
        lay.addRow("Input2", self.lineedit_b)
        lay.addRow("Steps:", self.stepProgressBar)
        lay.addRow("Progress:", self.valueProgressBar)
        lay.addRow("Diff:", self.textView)

        self.button.clicked.connect(self.handle_clicked)
        self.worker.stepChanged.connect(self.handle_step_changed)
        self.worker.progressChanged.connect(self.handle_progress_changed)
        self.worker.diffTextChanged.connect(self.handle_diff_text)

    @cached_property
    def stepProgressBar(self):
        return QtWidgets.QProgressBar(format="%m of %v")

    @cached_property
    def valueProgressBar(self):
        return QtWidgets.QProgressBar()

    @cached_property
    def button(self):
        return QtWidgets.QPushButton("Start")

    @cached_property
    def textView(self):
        return QtWidgets.QTextEdit(readOnly=True)

    @cached_property
    def lineedit_a(self):
        return QtWidgets.QLineEdit()

    @cached_property
    def lineedit_b(self):
        return QtWidgets.QLineEdit()

    @cached_property
    def worker(self):
        return Worker()

    def handle_clicked(self):
        self.worker.start(self.lineedit_a.text(), self.lineedit_b.text())

    def handle_step_changed(self, value, maximum):
        self.stepProgressBar.setMaximum(maximum)
        self.stepProgressBar.setValue(value)

    def handle_progress_changed(self, value, maximum):
        self.valueProgressBar.setMaximum(maximum)
        self.valueProgressBar.setValue(value)

    def handle_diff_text(self, text):
        self.textView.setText(text)


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)

    view = Viewer()
    view.resize(640, 480)
    view.show()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

Upvotes: 2

Related Questions