Search code examples
c++qtqmldatamodelqabstractlistmodel

Use a QAbstractListModel in another one


I have an issue while trying to develop a data model for my application with Qt/QML. I already used a QAbstractListModel to be able to pass customs data model from C++ to QML and it worked like a charm with simple model (such as a model based on strings and bools).

But now I need to build a more difficult model and I was wondering if it was possible to use a QAbstractListModel inside another QAbstractListModel.

Let me explain myself. I have a data model called model_A build like that :

model_A.h:

#ifndef MODEL_A_H
#define MODEL_A_H

#include <QAbstractListModel>
#include <QList>

class model_A
{
public:
   model_A(const QString& _string1,const QString& _string2,const bool& _bool);
   QString m_string1;
   QString m_string2;
   bool m_bool;
};
class abstractmodel_A : QAbstractListModel
{
   Q_OBJECT
public:
   (here I implemented all the roles functions and overloaded fonctions needed for the model to work)
private:
   QList<model_A> m_model_A;
};        
#endif // ANSWERS_H

And then I need to use that model inside another one called model_B:

model_B.h:

#ifndef MODEL_B_H
#define MODEL_B_H

#include <QAbstractListModel>
#include <QList>
#include "model_A.h"

class model_B
{
public:
   model_B(const QString& _string1,const QString& _string2,const abstractmodel_A& _modelA);
   QString m_string1;
   QString m_string2;
   abstractmodel_A m_modelA;
};
class abstractmodel_B : QAbstractListModel
{
   Q_OBJECT
public:
   (here I implemented all the roles functions and overloaded fonctions needed for the model to work)
   QList<model_B> m_model_B;
};        
#endif // ANSWERS_H

Is this possible, with all the restriction problem of the DISABLE_COPY of the QAbstractListModel or should I find another way to build my data model ?

Thank you.


Solution

  • In model_B, you can store a pointer to abstractmodel_A so DISABLE_COPY won't be a problem:

    class model_B
    {
    public:
       abstractmodel_A * m_modelA;
    };
    
    model_B modelBObject;
    modelBObject.m_modelA = new abstractmodel_A(/*parent*/);
    

    Next, create model_A_role in abstractmodel_B so QML can access model A in delegates. Inside abstractmodel_B::data function, you have to convert abstractmodel_A * to QVariant. Since abstractmodel_A inheirts from QAbstractListModel, which is a QObject, the type conversion can simply be done like this:

    QVariant abstractmodel_B::data(const QModelIndex &index, int role) const
    {
        //...
        if (role == Model_A_Role)
        {
            return QVariant::fromValue<QObject *>(m_model_B[index.row()].m_modelA);
        }
    }
    

    Finally back to QML, use ListView to handle C++ models:

    ListView {
        model: model_B
        delegate: Item {
            ListView {
                model: model_A_role
                delegate: DelegateForModelA { /*...*/ }
            }
            //...
        }
    }
    

    And DelegateForModelA can directly access roles in model_A.