[PyQt] Animated Progress Bars in QTableView - how?

Dave Gradwell davegradwell at yahoo.co.uk
Fri May 30 11:56:56 BST 2014

Hi List,

I have a QTableView in which I want to draw a column with progress bars.
I considered the Qt Torrent example application and re-implemented the paint function of the QStyledItemDelegate like this:

    def paint(self, painter, option, index):
        if index.column() == 1:

            progressBar = QtGui.QStyleOptionProgressBarV2()
            progressBar.state = QtGui.QStyle.State_Enabled
            progressBar.direction = QtGui.QApplication.layoutDirection()
            progressBar.rect = option.rect
            progressBar.fontMetrics = QtGui.QApplication.fontMetrics()
            progressBar.minimum = 0
            progressBar.maximum = 100
            progressBar.textAlignment = QtCore.Qt.AlignCenter
            progressBar.textVisible = True

            progressBar.progress = 20 # for testing

            QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_ProgressBar, progressBar, painter)

        return super(progressBarDelegate, self).paint(painter, option, index)

However, this gave me a column of greyed-out progress bars - with no animation.  
This isn't what the screenshots in the docs portray of the example.

Then I found out about QTableView's setIndexWidget().
I tried to implement setIndexWidget() whenever data() was called on the model but no progress bars were shown.
So I thought I'd try setIndexWidget() in the delegate paint() code.
I created a dictionary (self.parent.progressBarPool) to track which progress bars had been manufactured - to avoid excessive creation/deletion I guess.

    def paint(self, painter, option, index):
        if index.column() == 1:

            if not index.row() in self.parent.progressBarPool:
                progressBar = QtGui.QProgressBar()
                self.parent.progressBarPool[index.row()] = progressBar
                # progressBar.setAutoFillBackground(True) # docs say this needs to be true, but you get a better row-highlight appearance with it False
                self.parent.tableView.setIndexWidget(index, progressBar)
                progressBar = self.parent.progressBarPool[index.row()]

            progressBar.setValue(20) # for testing

        return super(progressBarDelegate, self).paint(painter, option, index)

This looked great...
... however, when I scrolled, the progress bars didn't move in concert with the rest of the scroll area.  
They floated above the cells which scrolled away underneath them.

I've now hacked things a bit so that the self.parent.progressBarPool is deleted when there's a wheelEvent.
This causes a flickery redraw on (one type of) scroll but feels like a growing stack of hacks rather than a solution.
Accordingly, I would appreciate any advice on the right way to do this.

With thanks,


pyqt 4.10.1
qt 4.8.4
Mac OS 10.6.8

Also posted this question on Stack Overflow:

More information about the PyQt mailing list