Here is my issue:
I have a program, that downloads roms off the internet. Everything works fine, but I would like to show an indefinite progress bar while it is downloading. I have that with the following code:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'progressbar.ui'
#
# Created: Fri Jun 04 12:59:51 2010
#      by: PyQt4 UI code generator 4.7.3
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

class Ui_ProgressBar(QtGui.QWidget):
    def setupUi(self, ProgressBar):
        ProgressBar.setObjectName("ProgressBar")
        ProgressBar.resize(261, 101)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(ProgressBar.sizePolicy().hasHeightForWidth())
        ProgressBar.setSizePolicy(sizePolicy)
        ProgressBar.setMaximumSize(QtCore.QSize(262, 101))
        self.progressBar = QtGui.QProgressBar(ProgressBar)
        self.progressBar.setGeometry(QtCore.QRect(10, 50, 241, 21))
        self.progressBar.setMaximum(0)
        self.progressBar.setProperty("value", -1)
        self.progressBar.setAlignment(QtCore.Qt.AlignCenter)
        self.progressBar.setTextVisible(True)
        self.progressBar.setOrientation(QtCore.Qt.Horizontal)
        self.progressBar.setInvertedAppearance(False)
        self.progressBar.setTextDirection(QtGui.QProgressBar.BottomToTop)
        self.progressBar.setObjectName("progressBar")
        self.Downloading = QtGui.QLabel(ProgressBar)
        self.Downloading.setGeometry(QtCore.QRect(0, 0, 261, 41))
        self.Downloading.setObjectName("Downloading")
        self.partofpart = QtGui.QLabel(ProgressBar)
        self.partofpart.setGeometry(QtCore.QRect(0, 80, 261, 20))
        self.partofpart.setObjectName("partofpart")

        #self.retranslateUi(ProgressBar)
        #QtCore.QMetaObject.connectSlotsByName(ProgressBar)

    def retranslateUi(self, ProgressBar, part1, part2):
        ProgressBar.setWindowTitle(QtGui.QApplication.translate("ProgressBar", "Form", None, QtGui.QApplication.UnicodeUTF8))
        self.progressBar.setFormat(QtGui.QApplication.translate("ProgressBar", "%p%", None, QtGui.QApplication.UnicodeUTF8))
        self.Downloading.setText(QtGui.QApplication.translate("ProgressBar", "<font size=\'25\'><center>Downloading...</center></font>", None, QtGui.QApplication.UnicodeUTF8))
        self.partofpart.setText(QtGui.QApplication.translate("ProgressBar", "<center>Part %s of %s</center>" %(part1, part2), None, QtGui.QApplication.UnicodeUTF8))

    def __init__(self, part1, part2):
        QtGui.QWidget.__init__(self)
        self.setupUi(self)
        self.retranslateUi(self, part1, part2)

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    PB = Ui_ProgressBar(2, (3))
    PB.show()
    sys.exit(app.exec_())

That works fine. This is the issue that I am having. I have the following code, but the gui of the program freezes while it is downloading.

#EXCERPT
    def dlfile(self):
        QtGui.QMessageBox.question(self, "Downloading",
                                       "<html><center>There are %s parts<br />Please wait while all are downloaded</center></html>" %(len(self.curgame)),
                                       QtGui.QMessageBox.NoButton)
        counter = 1
        for x in self.curgame:
            print(self)
            # Set the bar
            self.PB = Ui_ProgressBar(counter, len(self.curgame))
            self.PB.show()
            # Download it
            DL = DownloadLink(x, DownloadLink.abbrs2[str(self.system)])
            self.PB.hide()
            self.dl = 0
            counter += 1

I've tried so much to get this working, even threads. Can anyone give me any tips?

Dani AI

Generated

Short diagnosis: the progress bar only animates when the Qt event loop is free. In your loop you show a QProgressBar but then call a blocking DownloadLink(...) call on the main thread, so the event loop never runs and the widget appears frozen. As suggested, the correct fix is to move blocking work off the GUI thread (or use Qt's asynchronous network APIs).

A safe, maintainable pattern in PyQt4 is a QObject "worker" moved into a QThread and communicating with the GUI by signals. Example sketch (PyQt4 style):

from PyQt4 import QtCore

class DownloadWorker(QtCore.QObject):
    progress = QtCore.pyqtSignal(int)
    finished = QtCore.pyqtSignal()
    error = QtCore.pyqtSignal(str)

    def __init__(self, url):
        super(DownloadWorker, self).__init__()
        self.url = url

    @QtCore.pyqtSlot()
    def run(self):
        import urllib2
        try:
            resp = urllib2.urlopen(self.url)
            total = int(resp.headers.get('Content-Length') or 0)
            downloaded = 0
            while True:
                chunk = resp.read(8192)
                if not chunk:
                    break
                downloaded += len(chunk)
                if total:
                    self.progress.emit(int(100 * downloaded / total))
            self.finished.emit()
        except Exception as e:
            self.error.emit(str(e))

Start it from the GUI like this (minimal):

thread = QtCore.QThread()
worker = DownloadWorker(url)
worker.moveToThread(thread)
worker.progress.connect(self.progressBar.setValue)
thread.started.connect(worker.run)
worker.finished.connect(thread.quit)
thread.start()
self.progressBar.setMaximum(0)  # indeterminate while starting

Extra tips: never call GUI methods directly from the worker thread — use signals. Avoid modal message boxes or thread.join() on the main thread (that will freeze UI). Clean up with thread.finished.connect(thread.deleteLater) and worker.deleteLater. For many simultaneous downloads consider QThreadPool/QRunnable or QtNetwork's QNetworkAccessManager so everything stays in the Qt event loop. For : reuse one progress dialog for better UX (or show per-file indeterminate bar with setMaximum(0) and switch to percent updates when Content-Length is available).

You would use threads, although I use multiprocessing so am not that familiar with threading but here is a link to Doug Hellmann's examples The kicker is that the variable used to store the downloaded link must be visible to all threads so the progress bar can calculate the downloaded_size / total_download and display that in the progress bar every second or so. The GUI "freezes" in the current code because it has to wait until
DL = DownloadLink(x, DownloadLink.abbrs2[str(self.system)])
is completely finished to return to the for() loop and update the GUI.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.