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()
Related posts
- PyQt: How to pass arguments while emitting a signal — posted 2008-01-29
- How to install pyqt4 on ubuntu linux — posted 2008-01-15
- Python PyQt Tab Completion example — posted 2008-01-04
- How to capture the Tab key press event with PyQt 4.3 — posted 2008-01-03
- PyQt 4.3 Simple QAbstractListModel/ QlistView example — posted 2008-01-03
Comments
It is awesome! Can you do the code for type of font and size?
maybe getting rid of that selection box around txt.
I don't quite get how it all works....
Very helpful thanks.
I adjusted your code to match the default black-on-white (unselected) and white-on-blue (selected) colouring I'm getting in my QTableWidget. I also removed the validation as my values are known to always be strings.
class RetainSelectionHighlightDelegate(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(QColor("#3399FF"))
else:
painter.setBrush(QBrush(Qt.white))
painter.drawRect(option.rect)
set text color
value = index.data(Qt.DisplayRole)
if option.state & QStyle.State_Selected:
painter.setPen(QPen(Qt.white))
else:
painter.setPen(QPen(Qt.black))
Left indent
painter.translate(3, 0)
painter.drawText(option.rect, Qt.AlignLeft, value)
painter.restore()
disqus:2251702897