Paint widget directly on QListView with QStyledItemDelegate :: paint ()

After hours of work, I can draw a widget on a QListView . However, the picture is done through QPixmap . A widget will appear and I see a progress bar. However, it is a bit pixelated (due to the use of QPixmap ). Is it possible to draw directly as a regular widget? This is my question.

The following is what I am doing:

 void FileQueueItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QPaintDevice* original_pdev_ptr = painter->device(); FileQueueListItem* itemWidget = reinterpret_cast<FileQueueListItem*>(index.data(Qt::UserRole).value<void*>()); itemWidget->setGeometry(option.rect); painter->end(); QPixmap pixmap(itemWidget->size()); if (option.state & QStyle::State_Selected) pixmap.fill(option.palette.highlight().color()); else pixmap.fill(option.palette.background().color()); itemWidget->render(&pixmap,QPoint(),QRegion(),QWidget::RenderFlag::DrawChildren); painter->begin(original_pdev_ptr); painter->drawPixmap(option.rect, pixmap); } 

I learned how to do what I did with the tips here . There, the picture is executed directly on QListView , which I want to achieve. What am I doing wrong for the next attempt not to work:

 void FileQueueItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { std::cout<<"Painting..."<<std::endl; QPaintDevice* original_pdev_ptr = painter->device(); FileQueueListItem* itemWidget = reinterpret_cast<FileQueueListItem*>(index.data(Qt::UserRole).value<void*>()); itemWidget->setGeometry(option.rect); painter->end(); if (option.state & QStyle::State_Selected) painter->fillRect(option.rect, option.palette.highlight()); else painter->fillRect(option.rect, option.palette.background()); itemWidget->render(painter->device(), QPoint(option.rect.x(), option.rect.y()), QRegion(0, 0, option.rect.width(), option.rect.height()), QWidget::RenderFlag::DrawChildren); painter->begin(original_pdev_ptr); } 

The list remains empty and nothing happens. Although the selection can be seen, the widget is not displayed.

+2
source share
1 answer

Let's make a few understandable:

  • You should not create widgets and put them in a model. There is a good reason for this. Widgets participate in the Qt event loop, which means that too many widgets will significantly slow down your program.

  • Widgets are not just a bunch of controls (which seem to see them). They take part in the event loop, so you should not have a widget that is part of the data model.

  • If you use a multi-threaded program and your model is separate from the view, memory management will become a nightmare. Qt will never tolerate attempts to build or remove any widgets from other threads (which makes sense since disconnecting threads from the event loop is not generally thread safe).

Given this information, what is the right way to do what you are trying to do? Unfortunately, the only right way is to make the controls themselves. If your widget is simple, it is easy to do. If your widget is complex, you need a lot of math to calculate the position of each widget.

In the Qt Torrent Example, you will see how the progress bar is displayed. All you need to do is to draw the controls, calculate the position and use the rect member variable as the containing rectangle of the controls, and then draw them (of course, after setting their values). The paint() function has an option.rect parameter in it, which is the rectangle of the entire element. All you have to do is use math to calculate the positions inside this rectangle for each widget.

PS: NEVER USE ABSOLUTE VALUES FOR POSITIONS. You will never get it right, especially for different DPIs.

This will bring up the controls without widgets and guarantee the speed you need even for thousands of items.

+1
source

Source: https://habr.com/ru/post/1271427/


All Articles