Saltycrane logo

SaltyCrane Blog

Notes on Python, Django, and web development on Ubuntu Linux

    

PyQt4 QItemDelegate example with QListView and QAbstractListModel

I am currently working on a mini project which uses a QListView to display items in a list box. I am happy with most of the default behavior in the list view, however, I want to change how the highlighting of selected items is displayed. Currently, in my Windows environment, selecting an item in the list highlights the item in dark blue. This is fine, however, when the list box loses focus, the highlight color turns to a light gray, which is hard for me to see. I would like the selection to have a red highlight, whether the widget has focus or not.

My solution is to add a custom delegate to my list view. Normally, a standard view uses a default delegate (QItemDelegate) to render and edit the model's data. To customize the way the data is displayed in the view, I subclass QItemDelegate and implement a custom paint() method to set the background color to red for selected items. (Note, it is possible to specify certain formatting (including background color) using ItemDataRoles in the QAbstractListModel subclass, however, using a custom delegate is more powerful, and I didn't want to mix appearance-related code with my data model.)

In the example below, I started with the simple QListView / QAbstractListModel example, and added MyDelegate, a subclass of QItemDelegate. This class reimplements the paint() method to highlight selected items in red.

See also: Qt 4.3 QItemDelegate documentation

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

####################################################################
def main():
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

####################################################################
class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)

        # create objects
        list_data = [1,2,3,4]
        lm = MyListModel(list_data, self)
        de = MyDelegate(self)
        lv = QListView()
        lv.setModel(lm)
        lv.setItemDelegate(de)

        # layout
        layout = QVBoxLayout()
        layout.addWidget(lv)
        self.setLayout(layout)

####################################################################
class MyDelegate(QItemDelegate):
    def __init__(self, parent=None, *args):
        QItemDelegate.__init__(self, parent, *args)

    def paint(self, painter, option, index):
        painter.save()

        # set background color
        painter.setPen(QPen(Qt.NoPen))
        if option.state & QStyle.State_Selected:
            painter.setBrush(QBrush(Qt.red))
        else:
            painter.setBrush(QBrush(Qt.white))
        painter.drawRect(option.rect)

        # set text color
        painter.setPen(QPen(Qt.black))
        value = index.data(Qt.DisplayRole)
        if value.isValid():
            text = value.toString()
            painter.drawText(option.rect, Qt.AlignLeft, text)

        painter.restore()

####################################################################
class MyListModel(QAbstractListModel):
    def __init__(self, datain, parent=None, *args):
        """ datain: a list where each item is a row
        """
        QAbstractTableModel.__init__(self, parent, *args)
        self.listdata = datain

    def rowCount(self, parent=QModelIndex()):
        return len(self.listdata)

    def data(self, index, role):
        if index.isValid() and role == Qt.DisplayRole:
            return QVariant(self.listdata[index.row()])
        else:
            return QVariant()

####################################################################
if __name__ == "__main__":
    main()

Post a comment

Required
Required, but not displayed
Optional

Format using Markdown. (No HTML.)
  • Code blocks: prefix each line by at least 4 spaces or 1 tab (and a blank line before and after)
  • Code span: surround with backticks
  • Blockquotes: prefix lines to be quoted with >
  • Links: <URL>
  • Links w/ description: [description](URL)
Created with Django | Hosted by Linode