Search code examples
qtqwidgetqpainterqlistviewqstyleditemdelegate

Render QWidget in paint() method of QWidgetDelegate for a QListView


i'm having difficulties implementing custom widget rendering in a QListView. I currently have a QListView displaying my custom model called PlayQueue based on QAbstractListModel.

This is working fine with simple text, but now I would like to display a custom widget for each element. So I subclassed a QStyledItemDelegate to implement the paint method like this:

void QueueableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
    if (option.state & QStyle::State_Selected)
        painter->fillRect(option.rect, option.palette.highlight());
    QWidget *widget = new QPushButton("bonjour");
    widget->render(painter);
}

The selection background is properly rendered but no widget is displayed. I tried with simple QPainter commands like in Qt examples, and this is working fine:

void QueueableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
    if (option.state & QStyle::State_Selected)
        painter->fillRect(option.rect, option.palette.highlight());
    if (option.state & QStyle::State_Selected)
        painter->setPen(option.palette.highlightedText().color());
    painter->setFont(QFont("Arial", 10));
    painter->drawText(option.rect, Qt::AlignCenter, "Custom drawing");
}

So I tried some changes like:

  • Changing QStyledItemDelegate to QItemDelegate
  • Adding painter->save() and painter->restore() around rendering
  • Setting the widget geometry to the available size

But i'm a bit stuck now, i searched for a while on the internet, but can't find any example doing what i want, they all talk about editing widget (which is a lot easier) or custom drawn control (predefined ones, like progress bars). But here I really need a custom widget I created, containing some layout, labels & pixmaps. Thanks for your help!

I'm using Qt 4.7.3 for GCC on Ubuntu 11.04.


Solution

  • Ok I finally figured out how to do what I wanted. Here is what I did:

    1. Drop the delegate class
    2. Call QListView::setIndexWidget() in the data() method of my model to set the widget
    3. Ensure no widget is already present when setting by checking QListView::indexWidget()
    4. Handle the Qt::SizeHintRole role to return the widget's size hint
    5. Return a blank QVariant for the Qt::DisplayRole role

    This way I have my custom widgets displayed in the QListView, and they are properly lazy-loaded (that's why i used the model/view pattern). But I don't see how can I unload them when not beeing displayed, well that's another problem.