在 Qt 视图中使用 QWidget
Posted
技术标签:
【中文标题】在 Qt 视图中使用 QWidget【英文标题】:Using a QWidget in a Qt View 【发布时间】:2011-03-03 18:32:58 【问题描述】:问题:我想在视图中显示一个简单的 QStringListModel。但是,我希望视图中的每个项目都是我创建的自定义 QWidget。我不明白为什么这是一个如此困难的问题!我已经在互联网上搜索了解决方案,虽然我在这里和那里找到了一些零碎的东西,但没有一个好的解决方案可以满足我的所有需求。
设置我的模型/视图的基本代码:
QStringList strings;
// add some strings to the model
QStringListModel* model = new QStringListModel(strings);
QListView* view = new QListView;
view->setModel(model);
我已经尝试了各种尝试,但都无济于事。
尝试 #1
我尝试子类化一个新的 QItemDelegate 对象。在这个对象中,我覆盖了创建编辑器的方法。我遵循了设置该委托的所有步骤。问题是当视图填充模型时,它会在 Qt::DisplayRole 中抓取模型中的每个项目,而我需要它来抓取 Qt::EditRole 中的每个项目。
尝试 #2
我尝试的另一种方法是继承 QListView,并覆盖 setModel 方法以为模型中的每个项目调用 setIndexWidget。我的代码看起来像这样:
void CustomListView::setModel(QAbstractItemModel* model)
QListView::setModel(model);
for (int i = 0; i rowCount(); ++i)
QModelIndex index = model->index(i, 0);
CustomWidget* widget = new CustomWidget;
setIndexWidget(index, widget);
这可以将我的 CustomWidget 对象添加到列表视图中的每一行。为了确保常规模型数据也不会显示在我的 CustomWidget 对象下方,我还覆盖了 CustomListView::paintEvent(QPaintEvent* event) 什么都不做。再次,这奏效了。
但我现在的主要问题是,当列表显示时,虽然我的 CustomWidgets 显示正确,但列表的背景是纯白色。我尝试在 CustomListView 上调用 setAutoFillBackground(false) 但什么也没做。我希望我的列表视图具有透明背景。
我们将非常感谢对此问题的任何反馈。我花了很多时间试图让它工作!谢谢!
【问题讨论】:
所以,关于尝试 #2,我修复了背景问题。在我的 CustomListView 构造函数中,我调用了 viewport()->setAutoFillBackground(false)。对于这些方法或其他可能解决此问题的想法,我仍然很乐意提供更多反馈。 我认为你应该坚持代表。您还应该发布 setEditorData() 和 setModelData() 函数的来源。 不幸的是,我无法使列表中的所有项目都处于 EditMode 并使用委托中的 createEditor() 返回的 QWidget。似乎一次只能有一个项目处于该模式。 关于您对尝试 #2 的第一条评论,setItemWidget 的 qt 文档说:The given widget's autoFillBackground property must be set to true, otherwise the widget's background will be transparent, showing both the model data and the item at the given index.
所以您可能想尝试一下,而不是您所做的,这似乎是相反的。使用自定义委托似乎更自然。但是,当您已经有一个可以完成这项工作的自定义小部件时,必须重新实现 paint() 有点痛苦。能否以某种方式“劫持”您的小部件的绘制方法并在委托中使用它?
【参考方案1】:
我认为在 QStandardItemModel 中呈现自定义数据时遇到了类似的问题。我为解决它所做的是创建一个自定义 QStyledItemDelegate。 在createEditor方法中,可以测试:
if( qVariantCanConvert<YourObject>(index.data(Qt::YourRole)) )
然后创建您的编辑器,它实际上是您想要的自定义小部件。并使用模型中的数据设置其值。 为了自定义我的小部件,我使用了 CustomWidget.setStylesheet("background: blue");
之类的样式表如果您想要与编辑器完全相同的小部件,请在您的委托的绘制方法中。
CustomWidget renderer;
renderer.setText( index.data(Qt::DisplayRole).toString() );
renderer.resize(option.rect.size());
painter->save();
painter->translate(option.rect.topLeft());
renderer.render(painter);
painter->restore();
您必须自己处理 openPersistentEditor 和 closePersistentEditor。
希望它会有所帮助。
【讨论】:
【参考方案2】:我的建议是坚持使用自定义绘画的代表。
查看Star Delegate Example 像这样您以您想要的方式绘制(见下文),然后在获得焦点时使用createEditor
进行编辑。
void StarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
if (qVariantCanConvert<StarRating>(index.data()))
StarRating starRating = qVariantValue<StarRating>(index.data());
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
starRating.paint(painter, option.rect, option.palette,
StarRating::ReadOnly);
else
QStyledItemDelegate::paint(painter, option, index);
问题或作弊在于,您无需创建编辑器实例或使用drawControl()
将小部件置于编辑模式 即可绘制小部件。油漆代码见this question.
【讨论】:
以上是关于在 Qt 视图中使用 QWidget的主要内容,如果未能解决你的问题,请参考以下文章