Search code examples
pythonpyqt5qtableviewqprogressbar

How to include a column of progress bars within a QTableView?


I started creating a Plugin on QGIS 3 and my plugin requires Progress bars within a QTableView. I am trying to figure out how to add a column of progress bars within my QTableView in PyQt5. But I couldn't find any relevant code or resources regarding my problem.

My Table

        w= self.tasklist_tabv
        delegate = ProgressDelegate(w)
        w.setItemDelegateForColumn(2, delegate)

        w.setHorizontalHeaderLabels(["ID", "Name", "Progress"])

        for r, (_id, _name, _progress) in enumerate(data):

            it_id = QtGui.QTableWidgetItem(_id)
            it_name = QtGui.QTableWidgetItem(_name)
            it_progress = QtGui.QTableWidgetItem()
            chkBoxItem = QtGui.QTableWidgetItem()
            chkBoxItem.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
            chkBoxItem.setCheckState(QtCore.Qt.Unchecked)
            it_progress.setData(QtCore.Qt.DisplayRole+1000, _progress)
            w.insertRow(w.rowCount())

            for c, item in enumerate((it_id, it_name, it_progress)):
                w.setItem(r, c, item)

            for c, item  in enumerate((it_id, it_name, chkBoxItem)):
                w.setItem(r, c+1, item)

class ProgressDelegate(QtGui.QStyledItemDelegate):
def paint(self, painter, option, index):
    progress = index.data(QtCore.Qt.DisplayRole+1000)

    opt = QtGui.QStyleOptionProgressBar()
    opt.rect = option.rect
    opt.minimum = 0
    opt.maximum = 100
    opt.progress = progress
    opt.text = "{}%".format(progress)
    opt.textVisible = True
    QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_ProgressBar, opt, painter)

Solution

  • You can use a delegate:

    QTableView:

    - PyQt5

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    data = [("1", "Baharak", 10), ("2", "Darwaz", 60),
            ("3", "Fays abad", 20), ("4", "Ishkashim", 80), 
            ("5", "Jurm", 100)]
    
    class ProgressDelegate(QtWidgets.QStyledItemDelegate):
        def paint(self, painter, option, index):
            progress = index.data(QtCore.Qt.UserRole+1000)
            opt = QtWidgets.QStyleOptionProgressBar()
            opt.rect = option.rect
            opt.minimum = 0
            opt.maximum = 100
            opt.progress = progress
            opt.text = "{}%".format(progress)
            opt.textVisible = True
            QtWidgets.QApplication.style().drawControl(QtWidgets.QStyle.CE_ProgressBar, opt, painter)
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        w = QtWidgets.QTableView()
        delegate = ProgressDelegate(w)
        w.setItemDelegateForColumn(2, delegate)
        model = QtGui.QStandardItemModel(0, 3)
        model.setHorizontalHeaderLabels(["ID", "Name", "Progress"])
        for _id, _name, _progress in data:
            it_id = QtGui.QStandardItem(_id)
            it_name = QtGui.QStandardItem(_name)
            it_progress = QtGui.QStandardItem()
            it_progress.setData(_progress, QtCore.Qt.UserRole+1000)
            model.appendRow([it_id, it_name, it_progress])
        w.setModel(model)
        w.show()
        sys.exit(app.exec_())
    

    PyQt4

    from PyQt4 import QtCore, QtGui
    
    data = [("1", "Baharak", 10), ("2", "Darwaz", 60),
            ("3", "Fays abad", 20), ("4", "Ishkashim", 80), 
            ("5", "Jurm", 100)]
    
    class ProgressDelegate(QtGui.QStyledItemDelegate):
        def paint(self, painter, option, index):
            progress = index.data(QtCore.Qt.UserRole+1000)
            opt = QtGui.QStyleOptionProgressBar()
            opt.rect = option.rect
            opt.minimum = 0
            opt.maximum = 100
            if hasattr(progress, 'toPyObject'):
                progress = progress.toPyObject()
            opt.progress = progress
            opt.text = "{}%".format(progress)
            opt.textVisible = True
            QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_ProgressBar, opt, painter)
    
    if __name__ == '__main__':
        import sys
        app = QtGui.QApplication(sys.argv)
        w = QtGui.QTableView()
        delegate = ProgressDelegate(w)
        w.setItemDelegateForColumn(2, delegate)
        model = QtGui.QStandardItemModel(0, 3, w)
        model.setHorizontalHeaderLabels(["ID", "Name", "Progress"])
        for _id, _name, _progress in data:
            it_id = QtGui.QStandardItem(_id)
            it_name = QtGui.QStandardItem(_name)
            it_progress = QtGui.QStandardItem()
            it_progress.setData(_progress, QtCore.Qt.UserRole+1000)
            model.appendRow([it_id, it_name, it_progress])
        w.setModel(model)
        w.show()
        sys.exit(app.exec_())
    

    QTableWidget:

    - PyQt5

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    data = [("1", "Baharak", 10), ("2", "Darwaz", 60),
            ("3", "Fays abad", 20), ("4", "Ishkashim", 80), 
            ("5", "Jurm", 100)]
    
    class ProgressDelegate(QtWidgets.QStyledItemDelegate):
        def paint(self, painter, option, index):
            progress = index.data(QtCore.Qt.UserRole+1000)
            opt = QtWidgets.QStyleOptionProgressBar()
            opt.rect = option.rect
            opt.minimum = 0
            opt.maximum = 100
            opt.progress = progress
            opt.text = "{}%".format(progress)
            opt.textVisible = True
            QtWidgets.QApplication.style().drawControl(QtWidgets.QStyle.CE_ProgressBar, opt, painter)
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        w = QtWidgets.QTableWidget(0, 3)
        delegate = ProgressDelegate(w)
        w.setItemDelegateForColumn(2, delegate)
    
        w.setHorizontalHeaderLabels(["ID", "Name", "Progress"])
        for r, (_id, _name, _progress) in enumerate(data):
            it_id = QtWidgets.QTableWidgetItem(_id)
            it_name = QtWidgets.QTableWidgetItem(_name)
            it_progress = QtWidgets.QTableWidgetItem()
            it_progress.setData(QtCore.Qt.UserRole+1000, _progress)
            w.insertRow(w.rowCount())
            for c, item in enumerate((it_id, it_name, it_progress)):
                w.setItem(r, c, item)
        w.show()
        sys.exit(app.exec_())
    

    PyQt4

    from PyQt4 import QtCore, QtGui
    
    data = [("1", "Baharak", 10), ("2", "Darwaz", 60),
            ("3", "Fays abad", 20), ("4", "Ishkashim", 80), 
            ("5", "Jurm", 100)]
    
    class ProgressDelegate(QtGui.QStyledItemDelegate):
        def paint(self, painter, option, index):
            progress = index.data(QtCore.Qt.UserRole+1000)
            opt = QtGui.QStyleOptionProgressBar()
            opt.rect = option.rect
            opt.minimum = 0
            opt.maximum = 100
            if hasattr(progress, 'toPyObject'):
                progress = progress.toPyObject()
            opt.progress = progress
            opt.text = "{}%".format(progress)
            opt.textVisible = True
            QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_ProgressBar, opt, painter)
    
    if __name__ == '__main__':
        import sys
        app = QtGui.QApplication(sys.argv)
        w = QtGui.QTableWidget(0, 3)
        delegate = ProgressDelegate(w)
        w.setItemDelegateForColumn(2, delegate)
    
        w.setHorizontalHeaderLabels(["ID", "Name", "Progress"])
        for r, (_id, _name, _progress) in enumerate(data):
            it_id = QtGui.QTableWidgetItem(_id)
            it_name = QtGui.QTableWidgetItem(_name)
            it_progress = QtGui.QTableWidgetItem()
            it_progress.setData(QtCore.Qt.UserRole+1000, _progress)
            w.insertRow(w.rowCount())
            for c, item in enumerate((it_id, it_name, it_progress)):
                w.setItem(r, c, item)
        w.show()
        sys.exit(app.exec_())
    

    enter image description here