简体   繁体   English

在Qt视图中使用QWidget

[英]Using a QWidget in a Qt View

Problem: I have a simple QStringListModel that I want to display in a view. 问题:我想在视图中显示一个简单的QStringListModel。 However, I want each item in the view to be a custom QWidget that I have created. 但是,我希望视图中的每个项目都是我创建的自定义QWidget。 I do not understand why this is such a difficult problem! 我不明白为什么这是一个如此困难的问题! I have scoured the internet for solutions and, although I find bits and pieces here and there, no good solution fits all my needs. 我已经在互联网上寻找解决方案,尽管我发现这里和那里的点点滴滴,但没有一个好的解决方案能满足我的所有需求。

The basic code for setting up my model/view: 设置模型/视图的基本代码:


QStringList strings;
// add some strings to the model

QStringListModel* model = new QStringListModel(strings);
QListView* view = new QListView;

view->setModel(model);

I have tried various attempts at doing this to no avail. 我尝试过这样做的各种尝试无济于事。

Attempt #1 尝试#1

I tried subclassing a new QItemDelegate object. 我尝试了继承新的QItemDelegate对象。 Inside this object, I overrode the methods for creating an editor. 在这个对象中,我重写了创建编辑器的方法。 I followed all the steps for setting up that delegate. 我按照设置该委托的所有步骤进行了操作。 The problem is that when the view is populated with the model, it grabs each item in the model in Qt::DisplayRole when I need it to grab each item in Qt::EditRole. 问题是当视图用模型填充时,它在Qt :: DisplayRole中抓取模型中的每个项目,当我需要它来抓取Qt :: EditRole中的每个项目时。

Attempt #2 尝试#2

Another method I tried was to subclass a QListView, and override the setModel method to call setIndexWidget for each item in the model. 我尝试的另一种方法是子类化QListView,并覆盖setModel方法以为模型中的每个项调用setIndexWidget。 My code looks something this: 我的代码看起来像这样:


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

This worked as far as adding my CustomWidget object to each row in the list view. 这就像将CustomWidget对象添加到列表视图中的每一行一样。 In order to ensure that the regular model data was not also shown beneath my CustomWidget objects, I also overrode CustomListView::paintEvent(QPaintEvent* event) to do nothing. 为了确保常规模型数据不会显示在我的CustomWidget对象下面,我还覆盖了CustomListView :: paintEvent(QPaintEvent * event)什么都不做。 Again, this worked. 再次,这是有效的。

But my major issue now is that when the list is displayed, although my CustomWidgets are displayed on it properly, the background of the list is a solid white color. 但我现在的主要问题是,当显示列表时,虽然我的CustomWidgets正确显示在其上,但列表的背景是纯白色。 I tried calling setAutoFillBackground(false) on the CustomListView but that did nothing. 我尝试在CustomListView上调用setAutoFillBackground(false)但没有做任何事情。 I want my list view to have a transparent background. 我希望我的列表视图具有透明背景。

Any feedback on this problem would be greatly appreciated. 在这个问题上的任何反馈将不胜感激。 I have spent a lot of time trying to get this to work! 我花了很多时间试图让它发挥作用! Thanks! 谢谢!

I think I had a problem similar for rendering custom data in a QStandardItemModel. 我认为我在QStandardItemModel中渲染自定义数据时遇到了类似的问题。 What I did to solve it was to create a custom QStyledItemDelegate. 我解决它的方法是创建一个自定义QStyledItemDelegate。 In the createEditor method, you can test: 在createEditor方法中,您可以测试:

if( qVariantCanConvert<YourObject>(index.data(Qt::YourRole)) )

Then create your editor which is actually the custom widget you want. 然后创建您的编辑器,它实际上是您想要的自定义小部件。 And set its value with data from your model. 并使用模型中的数据设置其值。 To customize my widget I used stylesheets like CustomWidget.setStylesheet("background: blue"); 为了自定义我的小部件,我使用了样式表,如CustomWidget.setStylesheet(“background:blue”);

In the paint method of your delegate if you want the same widget you do exactly like you did with the editor. 在你的委托的paint方法中,如果你想要相同的小部件,你就像使用编辑器一样。

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

You'll have to handle yourself the openPersistentEditor and closePersistentEditor. 你必须自己处理openPersistentEditor和closePersistentEditor。

Hope it will help. 希望它会有所帮助。

My suggestion is to stick to delegates with custom painting. 我的建议是坚持使用自定义绘画的代表。

See the Star Delegate Example Like this you paint (see below) the way you want and then edit with createEditor when you get the focus. 请参阅Star Delegate示例如下所示,您可以根据需要绘制(见下文),然后在获得焦点时使用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);
     }
 }

The catch or the cheat is that you can paint your widget without creating an editor instance or having your widget in edit mode using drawControl() . 捕获或作弊是您可以在不创建编辑器实例或使用drawControl()将窗口小部件置于编辑模式的情况下 drawControl()窗口小部件。 See the paint code in this question. 请参阅此问题中的油漆代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM