【问题标题】:Paint widget directly on QListView with QStyledItemDelegate::paint()使用 QStyledItemDelegate::paint() 直接在 QListView 上绘制小部件
【发布时间】:2017-06-03 13:53:12
【问题描述】:

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

以下是我的工作:

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

我通过here 的提示学会了如何做我所做的事情。在那里,绘画是直接在QListView 上完成的,这就是我想要实现的。以下尝试不起作用,我做错了什么:

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

列表仍然是空的,没有任何反应。虽然可以看到选择,但小部件不显示。

【问题讨论】:

  • 如果将painter-&gt;end(); 移动到itemWidget-&gt;render(...) 之前的行会怎样?
  • @putu 仍然可以看到选择,但看不到小部件。
  • 您是否尝试过类似示例中的方法,例如Star Delegate Example?也许你错过了一些东西,例如sizeHint。或者最好使用painter-&gt;save()painter-&gt;restore() 而不是begin, end。我无法提供更多建议,因为没有完整的代码。
  • @putu 另外 save() + restore() (在删除了所有 begin() 和 end() 之后)不起作用...相同的结果...选择有效,而渲染不起作用不行。

标签: c++ qt model-view-controller qt5 qitemdelegate


【解决方案1】:

让我们澄清一些事情:

  1. 您不应该创建小部件并将它们放入模型中。这是有充分理由的。 Qt 事件循环中涉及到小部件,这意味着拥有太多小部件会显着减慢您的程序。

  2. 小部件不仅仅是一堆控件(这似乎是您对它们的看法)。它们参与事件循环,这就是为什么您不应该将小部件作为数据模型的一部分。

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

根据这些信息,您想要做的事情的正确方法是什么?可悲的是,唯一正确的方法是自己绘制控件。如果您的小部件很简单,那很容易做到。如果您的小部件很复杂,您将需要大量数学来计算每个小部件的位置。

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

PS:切勿对位置使用绝对值。你永远不会做对,尤其是对于不同的 DPI。

这将在没有小部件的情况下绘制控件,并且即使对于数千个元素也能保证您需要的速度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-21
    • 1970-01-01
    • 2018-05-27
    • 2017-11-12
    • 1970-01-01
    相关资源
    最近更新 更多