在QWidgetDelegate的paint()方法中为QListView渲染QWidget

发布于 2024-11-16 22:59:49 字数 1610 浏览 3 评论 0原文

我在 QListView 中实现自定义小部件渲染时遇到困难。 我目前有一个 QListView,显示基于 QAbstractListModel 的名为 PlayQueue 的自定义模型。

这对于简单的文本工作得很好,但现在我想为每个元素显示一个自定义小部件。 因此,我子类化了 QStyledItemDelegate 来实现 paint 方法,如下所示:

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

选择背景已正确呈现,但没有显示任何小部件。我尝试使用简单的 QPainter 命令(如 Qt 示例中的命令),效果很好:

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

所以我尝试了一些更改,例如:

  • QStyledItemDelegate 更改为 QItemDelegate
  • 添加painter->save()painter->restore() 围绕渲染
  • 将小部件几何形状设置为可用大小

但我现在有点卡住了,我搜索了对于一个在互联网上,但找不到任何执行我想要的操作的示例,他们都谈论编辑小部件(这更容易)或自定义绘制控件(预定义的控件,例如进度条)。 但在这里我真的需要一个我创建的自定义小部件,其中包含一些布局、标签和内容。像素图。 感谢您的帮助!

我在 Ubuntu 11.04 上使用 Qt 4.7.3 for GCC。

i'm having difficulties implementing custom widget rendering in a QListView.
I currently have a QListView displaying my custom model called PlayQueue based on QAbstractListModel.

This is working fine with simple text, but now I would like to display a custom widget for each element.
So I subclassed a QStyledItemDelegate to implement the paint method like this:

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 properly rendered but no widget is displayed. I tried with simple QPainter commands like in Qt examples, and this is working 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 like:

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

But i'm a bit stuck now, i searched for a while on the internet, but can't find any example doing what i want, they all talk about editing widget (which is a lot easier) or custom drawn control (predefined ones, like progress bars).
But here I really need a custom widget I created, containing some layout, labels & pixmaps.
Thanks for your help!

I'm using Qt 4.7.3 for GCC on Ubuntu 11.04.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

空气里的味道 2024-11-23 22:59:49

只是为了完成整个图片:进一步可以找到使用委托将 QWidget 作为 QListView 项进行管理的代码。

我终于找到了如何使用其 Paint(...) 方法使其在 QStyledItemDelegate 的子类中工作。

它似乎比以前的解决方案对性能更有效,但是这个语句需要通过调查 setIndexWidget() 对创建的 QWidget 做了什么来验证=)。

最后,这是代码

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

Just to complete the whole picture: further one can find the code to manage the QWidget as QListView item using delegates.

I finally found out how to make it work within the subclass of QStyledItemDelegate using its paint(...) method.

It seems more effective for performance than previous solution, but this statement one needs to verify =) by investigation what does setIndexWidget() do with created QWidget.

So finally, 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's 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);   
};
何以心动 2024-11-23 22:59:49

好吧,我终于知道如何做我想做的事了。这就是我所做的:

  1. 删除委托类
  2. 在模型的 data() 方法中调用 QListView::setIndexWidget() 来设置小部件
  3. 确保没有小部件已存在通过检查QListView::indexWidget()进行设置时
  4. 处理Qt::SizeHintRole角色以返回小部件的大小提示
  5. 返回一个空白的QVariant Qt::DisplayRole 角色

这样我就可以在 QListView 中显示自定义小部件,并且它们可以正确地延迟加载(这就是我使用模型/视图模式的原因)。但我不知道如何在不显示时卸载它们,这是另一个问题。

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

  1. Drop the delegate class
  2. Call QListView::setIndexWidget() in the data() method of my model to set the widget
  3. Ensure no widget is already present when setting by checking QListView::indexWidget()
  4. Handle the Qt::SizeHintRole role to return the widget's size hint
  5. Return a blank QVariant for the Qt::DisplayRole role

This way I have my custom widgets displayed in the QListView, and they are properly lazy-loaded (that's why i used the model/view pattern). But I don't see how can I unload them when not beeing displayed, well that's another problem.

情痴 2024-11-23 22:59:49

这里是一个示例。
看来您需要使用 QStylePainter,但这只是为了绘图,据我所知,它的作用并不像真正的按钮。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文