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

I'm having difficulty performing custom widget rendering in a QListView . Currently, I have a QListView displaying my custom model called PlayQueue based on QAbstractListModel .

This works fine with plain text, but now I would like to display a custom widget for each item. Therefore, I subclassed QStyledItemDelegate to implement the paint method as follows:

 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 displayed correctly, but the widget is not displayed. I tried using simple QPainter commands, as in the Qt examples, and this works 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, for example:

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

But I am a bit stuck now, I have been looking for some time on the Internet, but cannot find any example of what I want, they all talk about editing a widget (which is much simpler) or user-drawn control (predefined, for example, indicators fulfillment). But here I really need my own widget, which I created, containing some layouts, labels, and bitmaps. Thank you for your help!

I am using Qt 4.7.3 for GCC on Ubuntu 11.04.

+7
source share
3 answers

Well, I finally figured out how to do what I wanted. Here is what I did:

  • Drop the delegate class
  • Call QListView::setIndexWidget() in the data() method of my model to set the widget
  • Make sure the widget is already present during customization by checking QListView::indexWidget()
  • Refer to the Qt::SizeHintRole role to return a widget size hint
  • Returns an empty QVariant for the Qt::DisplayRole role

This way I have my own custom widgets displayed in the QListView and they are properly lazy (so I used the model / view template). But I do not see how I can unload them if they are not displayed, which is another problem.

+3
source

Just to finish the whole picture: Next you can find the code to control the QWidget as a QListView element using delegates.

I finally learned how to make it work in the QStyledItemDelegate subclass using my paint (...) method.

It seems more efficient for performance than the previous solution, but this operator needs to be checked =) by researching what setIndexWidget () does with the QWidget created.

So here is the code:

 class PackageListItemWidget: public QWidget 

.....

 class PackageListItemDelegate: public QStyledItemDelegate 

.....

 void PackageListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { // here we have active painter provided by caller // by the way - we can't use painter->save() and painter->restore() // methods cause we have to call painter->end() method before painting // the QWidget, and painter->end() method deletes // the saved parameters of painter // we have to save paint device of the provided painter to restore the painter // after drawing QWidget QPaintDevice* original_pdev_ptr = painter->device(); // example of simple drawing (selection) before widget if (option.state & QStyle::State_Selected) painter->fillRect(option.rect, option.palette.highlight()); // creating local QWidget (that why i think it should be fasted, cause we // don't touch the heap and don't deal with a QWidget except painting) PackageListItemWidget item_widget; // Setting some parameters for widget for example // spec. params item_widget.SetPackageName(index.data(Qt::DisplayRole).toString()); // geometry item_widget.setGeometry(option.rect); // here we have to finish the painting of provided painter, cause // 1) QWidget::render(QPainter *,...) doesn't work with provided external painter // and we have to use QWidget::render(QPaintDevice *,...) // which creates its own painter // 2) two painters can't work with the same QPaintDevice at the same time painter->end(); // rendering of QWidget itself item_widget.render(painter->device(), QPoint(option.rect.x(), option.rect.y()), QRegion(0, 0, option.rect.width(), option.rect.height()), QWidget::RenderFlag::DrawChildren); // starting (in fact just continuing) painting with external painter, provided // by caller painter->begin(original_pdev_ptr); // example of simple painting after widget painter->drawEllipse(0,0, 10,10); }; 
+11
source

Here is an example for you. It seems that you need to use QStylePainter, but this is just for drawing, as I understand it, it does not act like a real button.

0
source

All Articles