使用QStyledItemDelegate :: paint()直接在QListView上绘制窗口小部件

时间:2017-06-03 13:53:12

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

经过数小时的工作,我能够在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);
}

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

1 个答案:

答案 0 :(得分:1)

让我们说清楚一些事情:

  1. 您不应该创建小部件并将它们放入模型中。这是一个很好的理由。小部件涉及 Qt事件循环,这意味着拥有太多小部件会显着降低程序速度。

  2. 小部件不仅仅是一堆控件(看起来就像你看到的那样)。他们参与事件循环,这就是为什么你不应该有一个小部件是数据模型的一部分。

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

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

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

    PS:永远不要使用绝对值来获得这些位置。你永远不会做对,特别是对于不同的DPI。

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