1

I am trying to make a listview component using QQuickItem and load its model using QAbstractListModel. Below are the steps which i tried.

listviewComponent.qml

ListView {
   required model

    delegate: Text {
        required property string type
        required property string size

        text: type + ", " + size
        }
}

Model.h

class Model
{
public:
    Model(const QString& type, const QString& size);

    QString type() const;
    QString size() const;

private:
    QString m_type;
    QString m_size;
};

class CustomModel : public QAbstractListModel
{
    Q_OBJECT
public:
    enum Roles {
        TypeRole = Qt::UserRole + 1,
        SizeRole
    };

    CustomModel(QObject* parent = 0);

    void addElement(const Model& pElement);

    int rowCount(const QModelIndex& parent = QModelIndex()) const;

    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;

protected:
    QHash<int, QByteArray> roleNames() const;
private:
    QList<Model> m_list;
};

Model.cpp

Model::Model(const QString& type, const QString& size)
    : m_type(type), m_size(size)
{
}

QString Model::type() const
{
    return m_type;
}

QString Model::size() const
{
    return m_size;
}

CustomModel::CustomModel(QObject* parent)
    : QAbstractListModel(parent)
{
}

void CustomModel::addElement(const Model &pElement)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_list << pElement;
    endInsertRows();
}

int CustomModel::rowCount(const QModelIndex& parent) const {
    Q_UNUSED(parent);
    return m_list.count();
}

QVariant CustomModel::data(const QModelIndex& index, int role) const {
    if (index.row() < 0 || index.row() >= m_list.count())
        return QVariant();

    const Model& mod = m_list[index.row()];
    if (role == TypeRole)
        return mod.type();
    else if (role == SizeRole)
        return mod.size();
    return QVariant();
}

QHash<int, QByteArray> CustomModel::roleNames() const {
    QHash<int, QByteArray> roles;
    roles[TypeRole] = "type";
    roles[SizeRole] = "size";
    return roles;
}

Myclass.h

class myclass : public QObject
{
    Q_OBJECT
public:
    myclass();

    inline int createUI(QQmlApplicationEngine &engine){
        QQuickWindow *window = qobject_cast<QQuickWindow*>(engine.rootObjects().at(0));
        if (!window) {
            qFatal("Error: Your root item has to be a window.");
            return -1;
        }

        QQuickItem *root = window->contentItem();

        window->setWidth(600);
        window->setHeight(500);

        QQmlComponent listviewComp(&engine, QUrl(QStringLiteral("qrc:/listviewComponent.qml")));
       
        CustomModel model;
        model.addElement(Model("Wolf", "Medium"));
        model.addElement(Model("Polar bear", "Large"));
        model.addElement(Model("Quoll", "Small"));

        QQuickItem *listview = qobject_cast<QQuickItem*>(listviewComp.createWithInitialProperties({ {"model", QVariant::fromValue(&model)} }));
        QQmlEngine::setObjectOwnership(listview, QQmlEngine::CppOwnership);
        listview->setParentItem(root);
        listview->setParent(&engine);
        listview->setProperty("objectName", "lv");
        listview->setWidth(200);
        listview->setHeight(100);
        listview->setX(250);
        listview->setY(30);
 
       window->show();

        return 0;
}
};

main.cpp

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    engine.load(url);

    QQmlContext *item = engine.rootContext();
    myclass myClass;
    item->setContextProperty("_myClass", &myClass);

    myClass.createUI(engine);

    return app.exec();
}

Problem: Listview is getting displayed but with only one row, but there are 3 rows added in CustomModel. I am assuming some problem with createWithInitialProperties, but couldnt able to crack it.

0

1 Answer 1

2

The problem is caused because "model" is a local variable that will be destroyed as soon as createUI is finished executing, and what you see as the first row is just a cache, you shouldn't actually see a row (it looks like a bug). The solution is to use the heap memory:

// ...
CustomModel *model =  new CustomModel(window);
model->addElement(Model("Wolf", "Medium"));
model->addElement(Model("Polar bear", "Large"));
model->addElement(Model("Quoll", "Small"));

QQuickItem *listview = qobject_cast<QQuickItem*>(listviewComp.createWithInitialProperties({ {"model", QVariant::fromValue(model)} }));
// ...
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.