C++ 在Qt视图中使用QWidget

C++ 在Qt视图中使用QWidget,c++,qt,qt4,C++,Qt,Qt4,问题:我想在视图中显示一个简单的QStringListModel。但是,我希望视图中的每个项目都是我创建的自定义QWidget。我不明白为什么这是一个如此困难的问题!我在互联网上搜寻解决方案,尽管我到处都能找到零碎的东西,但没有一个好的解决方案能满足我的所有需求 设置我的模型/视图的基本代码: QStringList strings; // add some strings to the model QStringListModel* model = new QStringListModel

问题:我想在视图中显示一个简单的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::EditRole中抓取每个项目时,它会在Qt::DisplayRole中抓取模型中的每个项目

尝试#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*事件)重写为不做任何事情。这再次奏效

但我现在的主要问题是,当列表显示时,尽管我的CustomWidget正确地显示在上面,但列表的背景是纯白的。我尝试在CustomListView上调用setAutoFillBackground(false),但没有任何效果。我希望我的列表视图有一个透明的背景


对此问题的任何反馈都将不胜感激。我花了很多时间试着让它工作!谢谢

我想我在QStandarItemModel中呈现自定义数据时遇到了类似的问题。我所做的是创建一个定制的QStyledItemDelegate。 在createEditor方法中,可以测试:

if( qVariantCanConvert<YourObject>(index.data(Qt::YourRole)) )
您必须自己处理openPersistentEditor和closePersistentEditor


希望这会有所帮助。

我的建议是坚持让学员进行定制绘画

如下图所示,以您想要的方式绘制(见下文),然后在获得焦点时使用
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);
     }
 }
void StarDelegate::paint(QPainter*painter,const qstyleoption视图项和选项,
常数QModelIndex和索引)常数
{
if(QVariantConvert(index.data())){
StarRating StarRating=qVariantValue(index.data());
if(option.state&QStyle::state_选中)
painter->fillRect(option.rect,option.palete.highlight());
starRating.paint(画师、option.rect、option.palete、,
星号:只读);
}否则{
QStyledItemDelegate::paint(油漆工、选项、索引);
}
}

陷阱或欺骗是,您可以使用
drawControl()
绘制小部件,而无需创建编辑器实例或使小部件处于编辑模式。请参见

中的绘制代码,因此,关于尝试2,我修复了背景问题。在CustomListView构造函数中,我调用了viewport()->setAutoFillBackground(false)。我仍然希望对这些方法或其他可能解决这个问题的想法有更多的反馈。我认为你们应该坚持代表们的意见。此外,您还应该发布setEditorData()和setModelData()函数的源代码。不幸的是,我无法使列表中的所有项都处于EditMode,并在委托中使用createEditor()返回的QWidget。似乎一次只能有一个项目处于该模式。关于您对尝试#2的第一次评论,setItemWidget的qt文档说:
给定小部件的autoFillBackground属性必须设置为true,否则小部件的背景将是透明的,在给定索引处同时显示模型数据和项目。
因此,您可能希望尝试这样做,而不是尝试您所做的事情,这似乎是相反的。使用自定义委托似乎更自然。但是,当您已经有了一个自定义小部件来完成这项工作时,必须重新实现paint(),这有点痛苦。是否可能以某种方式“劫持”小部件的绘制方法并在代理中使用它?
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);
     }
 }