使用QStyledItemDelegate :: paint()在QListView上直接绘制小部件 [英] Paint widget directly on QListView with QStyledItemDelegate::paint()

查看:996
本文介绍了使用QStyledItemDelegate :: paint()在QListView上直接绘制小部件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

经过数小时的工作,我可以在QListView上绘制小部件.但是,绘画是通过QPixmap完成的.小部件出现,我可以看到一个进度条.但是,它有点像素化"(由于使用QPixmap).是否可以直接将其绘制为普通小部件?这是我的问题.

After hours of work, I'm able to paint a widget on QListView. However, the painting is done through a QPixmap. The widget appears, and I can see a progress bar. However, it's a little "pixelated" (due to using QPixmap). Is it possible to paint directly as a normal widget? That's my question.

以下是我的工作:

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);
}

我从此处了解了如何处理提示.在那里,绘画直接在QListView上完成,这就是我想要实现的目标.我为以下尝试失败而做错了什么:

I learned how to do what I did with the hints from here. There, the painting is done directly on QListView, which is what I'm looking to achieve. What am I doing wrong for the following 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 just remains empty, and nothing happens. Though the selection can be seen, but the widget doesn't show up.

推荐答案

让我们澄清一些事情:

  1. 您不应创建小部件并将其放入模型中.有一个很好的理由.小部件参与了 Qt事件循环,这意味着过多的小部件将显着降低程序速度.

  1. You're not supposed to create widgets and put them in a model. There's a very good reason for this. Widgets are involved in the Qt event loop, which means that having too many widgets will significantly slow down your program.

小部件不仅是一堆控件(似乎就是您看到它们的方式).它们参与了事件循环,这就是为什么您不应该拥有作为数据模型一部分的小部件的原因.

Widgets are not simply a bunch of controls (which seems to be how you see them). They take part in the event loop, which is why you should not have a widget that's a part of a data model.

如果您使用的是多线程程序,并且模型与视图分离,那么内存管理将成为一场噩梦. Qt永远不会容忍试图从其他线程构造或删除任何小部件(这是有道理的,因为从事件循环中分离线程通常不是线程安全的.)

If you're using a multithreaded program and you have our model separated from the view, memory management will become a nightmare. Qt will never tolerate trying to construct or delete any widgets from other threads (which makes sense, since detaching threads from the event loop is not generally thread-safe).

鉴于此信息,做您想做的事情的正确方法是什么?遗憾的是,唯一正确的方法是自己绘制控件.如果您的小部件很简单,那很容易做到.如果您的窗口小部件很复杂,那么您将需要大量数学运算来计算每个窗口小部件的位置.

Given this information, what's the right way to do what you're trying to do? Sadly the only correct way is to draw the controls yourself. If your widget is simple, that's easy to do. If your widget is complicated, you're gonna need lots of math to calculate the positions of every widget.

Qt Torrent示例中,您将查看如何绘制进度条.绘制控件,要做的就是计算位置,并使用rect成员变量作为控件的包含矩形,然后绘制它们(当然,在设置它们的值之后).函数paint()中有一个option.rect参数,它是整个项目的矩形.您要做的就是使用一些数学运算来计算每个小部件在此矩形内的位置.

In the Qt Torrent Example, you'll see how a progress bar is drawn. All you have to do to draw your controls, is 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 function paint() has an option.rect parameter in it, which is the rectangle of the whole item. All you have to do, is use some math to calculate the positions inside this rect for every widget.

PS:切勿在位置上使用绝对值.您永远做不到,尤其是对于不同的DPI.

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

这将绘制不带窗口小部件的控件,并且即使是成千上万个元素,也可以保证所需的速度.

That will draw the controls without widgets, and will guarantee the speed you need even for thousands of elements.

这篇关于使用QStyledItemDelegate :: paint()在QListView上直接绘制小部件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆