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_()

Packaging Python Applications with PyInstaller by Martin Fitzpatrick — This step-by-step guide walks you through packaging your own Python applications from simple examples to complete installers and signed executables.

More info Get the book

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

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.