Изменение значения progress bar

Имеется такой код:

#main.py
import sys
from PyQt5 import QtWidgets
from main_window import MainWindow

if __name__ == "__main__":    
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

#main_window.py
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtWidgets import *
from PyQt5.Qt import *
from PyQt5.QtCore import (Qt, QObject, QThread, pyqtSignal)
from ui_main_window import Ui_MainForm
from work_thread_class import WorkThread

class MainWindow(QtWidgets.QWidget, Ui_MainForm):
    def __init__(self):
        super().__init__()
        self.setupUi(self)  
        self.progressBar.setDisabled(True)

        self.generate()

    def on_threadSignal(self, value):
        self.progressBar.setValue(value)

    def generate(self):
        self.progressBar.setValue(1)

        self.thread = WorkThread(self)
        self.thread.threadSignal.connect(self.on_threadSignal) 
        self.thread.start() 

        if self.progressBar.value() > 80:
            self.close_thread() 
            print("Поток закрыт")

#ui_main_window.py
from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainForm(object):
    def setupUi(self, MainForm):
        MainForm.setObjectName("MainForm")
        MainForm.resize(391, 508)
        self.progressBar = QtWidgets.QProgressBar(MainForm)
        self.progressBar.setEnabled(True)
        self.progressBar.setGeometry(QtCore.QRect(20, 390, 351, 23))
        self.progressBar.setMouseTracking(False)
        self.progressBar.setProperty("value", 0)
        self.progressBar.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop)
        self.progressBar.setTextVisible(True)
        self.progressBar.setOrientation(QtCore.Qt.Horizontal)
        self.progressBar.setInvertedAppearance(False)
        self.progressBar.setTextDirection(QtWidgets.QProgressBar.TopToBottom)
        self.progressBar.setObjectName("progressBar")

        self.retranslateUi(MainForm)
        QtCore.QMetaObject.connectSlotsByName(MainForm)

    def retranslateUi(self, MainForm):
        _translate = QtCore.QCoreApplication.translate
        MainForm.setWindowTitle(_translate("MainForm", "Loader"))
        self.progressBar.setFormat(_translate("MainForm", "%p%"))

#work_thread_class.py
from PyQt5.QtCore import (Qt, QThread, pyqtSignal)
from loader_class import Loader

class WorkThread(QThread):
    threadSignal = pyqtSignal(str)

    def __init__(self, parent):
        super().__init__()

        self.parent = parent

    def run(self):
        progressBar_Value = 0
        step = 1
        k = 0
        for i in range (0, 10):
            for j in range (0, 10):
                if k >= step:
                    k = 0
                    progressBar_Value += 1
                    self.parent.progressBar.setValue(progressBar_Value)
                else:
                    k += 1
                print("выполненo")
                

Программа должна во время прохода цикла изменять значение прогресс бара. Когда значение прогресс бара становится равным 80 поток должен закрыться.

В приведенном примере, программа зависает и закрывается.

Так же появилась надпись:

QWidget::repaint: Recursive repaint detected QObject::setParent: Cannot set parent, new parent is in a different thread

и почти почти после каждой итерации

QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?

Как решить эту проблему?

UDP: так же пробовал через эмитор передать значение

self.threadSignal.emit(progressBar_Value) ,

но сразу полностью зависает программа.


Ответы (1 шт):

Автор решения: S. Nick

Нельзя взаимодействовать с виджетами в дополнительном потоке.

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

from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.Qt import *
# ?from loader_class import Loader

#from ui_main_window import Ui_MainForm
class Ui_MainForm(object):
    def setupUi(self, MainForm):
        MainForm.setObjectName("MainForm")
        MainForm.resize(391, 508)
        self.progressBar = QtWidgets.QProgressBar(MainForm)
        self.progressBar.setEnabled(True)
        self.progressBar.setGeometry(QtCore.QRect(20, 390, 351, 23))
        self.progressBar.setMouseTracking(False)
        self.progressBar.setProperty("value", 0)
        self.progressBar.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop)
        self.progressBar.setTextVisible(True)
        self.progressBar.setOrientation(QtCore.Qt.Horizontal)
        self.progressBar.setInvertedAppearance(False)
        self.progressBar.setTextDirection(QtWidgets.QProgressBar.TopToBottom)
        self.progressBar.setObjectName("progressBar")

        self.retranslateUi(MainForm)
        QtCore.QMetaObject.connectSlotsByName(MainForm)

    def retranslateUi(self, MainForm):
        _translate = QtCore.QCoreApplication.translate
        MainForm.setWindowTitle(_translate("MainForm", "Loader"))
        self.progressBar.setFormat(_translate("MainForm", "%p%"))
        

#from work_thread_class import WorkThread
class WorkThread(QThread):
#    threadSignal = pyqtSignal(str)
    threadSignal = pyqtSignal(int)                              # +++
    
    def __init__(self, parent):
        super().__init__()
        self.parent = parent

    def run(self):
        progressBar_Value = 0
        for i in range(0, 10):
            for j in range(0, 10):
                progressBar_Value += 1
#                    self.parent.progressBar.setValue(progressBar_Value)
                self.threadSignal.emit(progressBar_Value)       # +++
                self.msleep(100)


class MainWindow(QtWidgets.QWidget, Ui_MainForm):
    def __init__(self):
        super().__init__()
        self.setupUi(self)  
        self.progressBar.setDisabled(True)

        self.generate()

    def on_threadSignal(self, value):
        self.progressBar.setValue(value)
        print(f'value = {value}') 
        if self.progressBar.value() > 79:
            self.thread.terminate()
            self.thread.wait()
            print("Поток закрыт")
            
    def generate(self):
        self.progressBar.setValue(1)
        self.thread = WorkThread(self)
        self.thread.threadSignal.connect(self.on_threadSignal)  # +++
        self.thread.start() 


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка