0

Here is some sample code that breaks:

import sys
import time
from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar)

class Actions(QDialog):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.show()

        self.count = 0

        while self.count < 100:
            self.count += 1
            time.sleep(1) # Example external function
            self.progress.setValue(self.count)

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

Running this will cause it to freeze and become unresponsive particularly in windows environments. Replacing the time.sleep function with any non-PyQt5 function will yield the same results.

From what I understand this has to do with the function not being called in a separate thread using QThread. I used this answer as a reference and came up with a partial solution.

import sys
import time

from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar)

class External(QThread):

    def run(self):
        count = 0

        while count < 100:
            count += 1
            print(count)
            time.sleep(1)

class Actions(QDialog):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.show()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Actions()
    calc = External()
    calc.finished.connect(app.exit)
    calc.start()
    sys.exit(app.exec_())

This will run time.sleep in the background and keep the main window responsive. But, I don't know how to update the values using self.progress.setValue since it's not accessible in class External.

So far from what I know, I have to use signals to accomplish this. Most of the documentation out there is for PyQt4 making it harder to find a solution.

Another problem I am faced with is being able to start the External thread from within class Actions.

Answers to this problem will also serve as valuable documentation for PyQt5. Thanks in advance.

Community
  • 1
  • 1
Vivek Joshy
  • 974
  • 14
  • 37
  • 1
    This answer shows how to wire an external thread to a progress bar via signals / slots. I think its applicable to qt5 http://stackoverflow.com/questions/9682376/progress-bar-with-pyqt – tdelaney Mar 26 '17 at 03:58

2 Answers2

1

You must use the signals to update the values.

import sys
import time

from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar)

class External(QThread):
    countChanged = pyqtSignal(int)
    def run(self):
        count = 0

        while count < 100:
            count += 1
            self.countChanged.emit(count)
            print(count)
            time.sleep(1)

class Actions(QDialog):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.show()

    def onCountChanged(self, value):
        self.progress.setValue(value)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Actions()
    calc = External()
    calc.countChanged.connect(window.onCountChanged)
    calc.start()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
0

Here is a version that starts the thread from inside class Actions and uses a button:

import sys
import time

from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar, QPushButton)

class External(QThread):

    countChanged = pyqtSignal(int)

    def run(self):
        count = 0

        while count < 100:
            count += 1
            time.sleep(1)
            print(count)
            self.countChanged.emit(count)

class Actions(QDialog):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.button = QPushButton('Start', self)
        self.button.move(0, 30)
        self.show()

        self.button.clicked.connect(self.onButtonClick)

    def onButtonClick(self):
        self.calc = External()
        self.calc.countChanged.connect(self.onCountChanged)
        self.calc.start()

    def onCountChanged(self, value):
        self.progress.setValue(value)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Actions()
    sys.exit(app.exec_())
Vivek Joshy
  • 974
  • 14
  • 37