我在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);
}
选择背景已正确渲染,但没有显示任何小部件。我尝试了像Qt示例中那样的简单QPainter
命令,这很好:
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上为GCC使用Qt 4.7.3。
只是为了完成整个画面:此外,还可以找到使用委托将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);
};
好吧,我终于想好了如何做我想做的事。以下是我所做的:
- 删除委托类
- 在我的模型的
data()
方法中调用QListView::setIndexWidget()
来设置小部件 - 通过检查
QListView::indexWidget()
确保设置时没有小部件 - 处理
Qt::SizeHintRole
角色以返回小部件的大小提示 - 为
Qt::DisplayRole
角色返回一个空白QVariant
通过这种方式,我的自定义小部件显示在QListView中,并且它们被适当地延迟加载(这就是我使用模型/视图模式的原因)。但我不知道如何在不显示的情况下卸载它们,这是另一个问题。
这里有一个例子。似乎你需要使用QStylePainter,但据我所知,这只是为了画画,它的行为不像一个真正的按钮。