Reputation: 133
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
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