Instead of trying to match some data with some elements of the model, each element stores its data. This includes using a delegate to draw and not rely on the QAbstractItemView paint event.
Let us have a simple state class to represent our item data and make it a new citizen in the Qt meta-object system using Q_DECLARE_METATYPE .
#include <QMetaType> class ItemData { public: ItemData() = default; ItemData(int d) : _data(d){} int data() const { return _data; } void paint(QPainter *painter, QRect rect); private: int _data; }; Q_DECLARE_METATYPE(ItemData)
Now the delegate, very simple, really:
#include <QStyledItemDelegate> class ItemDelegate : public QStyledItemDelegate { public: // ... void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; // ... };
The delegate drawing method is what happens:
void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if(index.data().canConvert<ItemData>()) { ItemData itemdata = qvariant_cast<ItemData>(index.data()); itemdata.paint(painter, option.rect); } else { QStyledItemDelegate::paint(painter, option, index); } }
Here we can use the model index for what this means: get element data. However, our element can draw itself. Let him draw a few circles in accordance with his inner state:
void ItemData::paint(QPainter *painter, QRect rect) { QRect r(rect.left() + 2, rect.top() + 2, rect.height() - 4, rect.height() - 4); for(int i=0; i<_data; ++i) { painter->drawEllipse(r); r.moveLeft(r.left() + rect.height() + 2); } }
In a more flexible design, data is separated from rendering, so the ItemData class ItemData not have a paint method, and painting is done by the delegate itself:
void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if(index.data().canConvert<ItemData>()) { ItemData itemdata = qvariant_cast<ItemData>(index.data());
Thus, we can implement and then choose different delegates for different representations, but keeping a single consistent model and sharing it among them.
Using a delegate and data in an elementary widget like QListWidget is simple. In the form constructor:
ui->listWidget->setItemDelegate(new ItemDelegate()); for(int i=0; i<10; ++i) { QListWidgetItem * item = new QListWidgetItem(); item->setData(0, QVariant::fromValue(ItemData(i + 1))); ui->listWidget->addItem(item); }
Not that different based on the model: instead of setting data to elements, the data is set to the model again using QVariant::fromValue .