c++qt5qwidgetqstyleditemdelegate

Why is my QStyledItemDelegate not visible?


I'm trying to create a custom item delegate for a list of objects, but when I run my app the list view is blank. I know my model is populated, and it displays as expected with the standard default delegate. I can also tell that my custom delegate is being rendered in some sense, since space is taken up in the list, and the tooltips and statustips that I set work, but the contents are not visible (the listview appears to be blank white).

My code is based on this example: https://doc.qt.io/archives/qt-5.12/qtwidgets-itemviews-stardelegate-example.html Qt 5.12 is the version that I'm stuck with, and I'm also stuck using visual studio without the normal Qt debugging tools, do to factors outside of my control.

Anyway, I create the widgets that should be displayed in the constructor, with default values for testing:

EntityListDelegate::EntityListDelegate(QWidget* parent /*= nullptr*/) : QStyledItemDelegate(parent)
    {
        ui = new QWidget(parent);
        ui->setMinimumSize(QSize(200, 40));
        QHBoxLayout* hLayout = new QHBoxLayout(ui);
        iconLabel = new QLabel(ui);
        iconLabel->setMinimumSize(QSize(20, 20));
        iconLabel->setMaximumSize(QSize(40, 40));
        iconLabel->setPixmap(QPixmap(":/icons/Placeholder.png"));
        hLayout->addWidget(iconLabel);
        QVBoxLayout* vLayout = new QVBoxLayout(ui);
        nameLabel = new QLabel(ui);
        nameLabel->setMinimumSize(QSize(150, 20));
        nameLabel->setText("Unknown entity");
        vLayout->addWidget(nameLabel);
        typeLabel = new QLabel(ui);
        typeLabel->setMinimumSize(QSize(150, 16));
        typeLabel->setText("Unknown type");
        vLayout->addWidget(typeLabel);
        hLayout->addLayout(vLayout);
        ui->setLayout(hLayout);
    }

Note that each item should have a thick black border, which is not being rendered. (Edit: I changed the QFrame back to a QWidget)

I also implemented paint, where the real values should get set based on info in the model:

void EntityListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
    {
        nameLabel->setText(index.data(Qt::DisplayRole).toString());
        switch (qvariant_cast<int>(index.data(UserRoles::Type)))
        {
            case EntityType::Foo:
            {
                iconLabel->setPixmap(QPixmap(":/icons/foo.png"));
                typeLabel->setText("Foo");
                break;
            }
            case EntityType::Bar:
            {
                iconLabel->setPixmap(QPixmap(":/icons/bar.png"));
                typeLabel->setText("Bar");
                break;
            }
            case EntityType::Baz:
            {
                iconLabel->setPixmap(QPixmap(":/icons/baz.png"));
                typeLabel->setText("Baz");
                break;
            }
            default:
                break;
        }
    }

The other functions are just stubs, since the user shouldn't be able to edit this data.

Am I missing some step in my setup?

Update: I tried making the pointer to the delegate that gets passed into setItemDelegate() a member of the class that owns the the ListView. I now get one item on the list that renders correctly, in the top position in the list. I can sometimes get it to display another item by clicking where that item should be, but it's still in the same location.


Solution

  • The answer to the question as asked is that if you're trying to alter the default display, not the editor, you have to reimplement paint and basically draw the whole thing manually. This is such a massive PITA as to make QStyledItemDelegate functionally unusable for this use case, IMO. Use QtQuick if you can, but that's not an option in my case.

    My actual solution, for the curious, was to use QSortFilterProxyModel and override data() to return "EntityName\nEntityType". That gets me ~80% of what I was trying to achieve, and hopefully I can get a little closer with styling when I get to that part.