Change color in QProgressBar delegate

Heads up! You've already completed this tutorial.

Vladislav_Alekseev | 2021-03-24 11:48:38 UTC | #1

Hello everyone! I want to make the progress of the process (QProgressBar)in QTableView, it already worked, but now I want to add a color change when the process stops. I don't understand how to do this with a delegate, I tried installing a new delegate, but it doesn't work (it doesn't redraw the color), I tried installing a standard delegate, but there are no changes. There is no range in the delegate, i.e. SetRange(0, 0) the process is either running (green) or not (red).

Example:

python
from PySide2 import QtCore, QtWidgets, QtGui


class ProgressBarDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent, color):
        super().__init__(parent)
        self.color = color

    def paint(self, painter, option, index):
        if index.column() == 2:
            if (isinstance(self.parent(), QtWidgets.QAbstractItemView)
                    and self.parent().model() is index.model()):
                self.parent().openPersistentEditor(index)
            QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)
        else:
            QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)

    def createEditor(self, parent: QtWidgets.QWidget, option: QtWidgets.QStyleOptionViewItem,
                     index: QtCore.QModelIndex) -> QtWidgets.QWidget:

        editor = QtWidgets.QProgressBar(parent)
        editor.setRange(0, 0)
        editor.setTextVisible(False)
        editor.setStyleSheet("QProgressBar:chunk {background-color:" + self.color + "; width: 20px; margin: 0.5px}")

        return editor


class PushButtonDelegate(QtWidgets.QStyledItemDelegate):
    clicked = QtCore.Signal(QtCore.QModelIndex)

    def paint(self, painter, option, index):
        if (isinstance(self.parent(), QtWidgets.QAbstractItemView)
                and self.parent().model() is index.model()):
            self.parent().openPersistentEditor(index)
        QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)

    def createEditor(self, parent, option, index):
        button = QtWidgets.QPushButton(parent)
        button.clicked.connect(lambda *args, ix=index: self.clicked.emit(ix))

        return button

    def setEditorData(self, editor, index):
        editor.setText("Start/Stop")

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)


class MyWidgetsForm(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        QtWidgets.QMainWindow.__init__(self, parent)

        self.initUi()
        self.initModel()

        self.pbDelegate.clicked.connect(self.onPBDelegateClicked)

    def onPBDelegateClicked(self, pushRow):
        print(self.tableView.model().index(pushRow.row(), 2).data())
        if self.tableView.model().index(pushRow.row(), 2).data() is None or self.tableView.model().index(pushRow.row(),
                                                                                                         2).data() == 0:
            prbarDelegate = ProgressBarDelegate(self.tableView, "green")
            self.tableView.setItemDelegateForRow(pushRow.row(), prbarDelegate)

            self.tableView.model().setData(self.tableView.model().index(pushRow.row(), 2), 1,
                                           QtCore.Qt.DisplayRole)

        elif self.tableView.model().index(pushRow.row(), 2).data() == 1:
            prbarDelegate = ProgressBarDelegate(self.tableView, "red")
            self.tableView.setItemDelegateForRow(pushRow.row(), prbarDelegate)

            self.tableView.model().setData(self.tableView.model().index(pushRow.row(), 2), 0,
                                           QtCore.Qt.DisplayRole)

    def initUi(self):
        self.setFixedSize(600, 300)

        self.tableView = QtWidgets.QTableView()
        layout = QtWidgets.QHBoxLayout()
        layout.addWidget(self.tableView)
        cw = QtWidgets.QWidget()
        cw.setLayout(layout)
        self.setCentralWidget(cw)

    def initModel(self):
        headers = ['Путь', 'Управление', 'Прогресс']
        self.pbDelegate = PushButtonDelegate(self.tableView)

        self.stm = QtGui.QStandardItemModel()
        self.stm.setHorizontalHeaderLabels(headers)

        for row in range(5):
            self.stm.setItem(row, 0, QtGui.QStandardItem("some_path" + str(row)))
            self.stm.setItem(row, 1, QtGui.QStandardItem())

        self.tableView.setModel(self.stm)
        self.tableView.clearSpans()
        self.tableView.setItemDelegateForColumn(1, self.pbDelegate)
        self.tableView.resizeColumnsToContents()
        self.tableView.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)


if __name__ == "__main__":
    app = QtWidgets.QApplication()

    myapp = MyWidgetsForm()
    myapp.show()

    app.exec_()

Over 10,000 developers have bought Create GUI Applications with Python & Qt!
Create GUI Applications with Python & Qt6
Take a look

Downloadable ebook (PDF, ePub) & Complete Source code

Also available from Leanpub and Amazon Paperback

[[ discount.discount_pc ]]% OFF for the next [[ discount.duration ]] [[discount.description ]] with the code [[ discount.coupon_code ]]

Purchasing Power Parity

Developers in [[ country ]] get [[ discount.discount_pc ]]% OFF on all books & courses with code [[ discount.coupon_code ]]
Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak
Martin Fitzpatrick

Change color in QProgressBar delegate was written by Martin Fitzpatrick .

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt. Martin founded PythonGUIs to provide easy to follow GUI programming tutorials to the Python community. He has written a number of popular Python books on the subject.