Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Access model owned by class in QML



  • Hi!

    I've seen several topics on similar problems, but I still haven't been able to solve it, so I'm making a new thread.

    I have a class, ModelManager, that owns an instance of MyListModel, inheriting from QAbstractListModel. The ModelManager is the .cpp backend that is exposed to QML through a call to setContextProperty in main.cpp.

    I would like to access myListModel in QML and use it as a model for a Repeater.

    My idea was to have the ModelManager own an instance of myListModel and have a Q_INVOKABLE getter in ModelManager.

    In ModelManager I have:

    class ModelManager : QObject
    {
    Q_OBJECT
    public:
    ModelManager(QObject* parent = 0);
    Q_INVOKABLE MyListModel* myListModel() {return &myListModel_;}
    private:
    MyListModel myListModel_;
    }
    

    And in the Repeater I want to write:

    Repeater
    {
    model: manager.myListModel()
    ...
    }
    

    I can't get it working however. I've read several posts about out it here on the forum. Some mention qmlRegisterType, which I've tried calling in my main.cpp with no luck.

    qmlRegisterType<MyListModel>("ListModel",1,0, "listModel");
    

    and then importing it with:

    import ListModel 1.0
    

    But no matter what I try, I always get the error:

    Unkown return type: MyListModel*
    

    I've also tried returing QObject* in myListModel(). This runs, but I get a very nasty error and crash, I'm assuming when the Repeater actually tries to access the model.

    Any ideas about what I'm getting wrong?



  • @Obi-Wan you don't need to have a Q_INVOKABLE getter to expose your MyListModel into QML components instead use QQmlContext class, try it this way:

    //main.cpp
    QQmlContext *context = new QQmlContext(engine.rootContext());
    context->setContextProperty("myListModel", &myListModel);
    
    //qml file
    Repeater
    {
       model: myListModel
       ...
    }


  • @literA2 Thanks!

    This seems to work, as in the text turns blue if I write myListModel in QML, but I'm having a hard time confirming if it does!

    myListModel currently is a list of doubles, I tought I could should these in a QML window by writing:

    ListView
    {
    id: testView
    width: 200
    height: 200
    x: 50
    y: 50
    model: myListModel
    
    delegate: Text {
    text: display // As this is the default role
    }
    

    Shouldn't this work?



  • @Obi-Wan in order to use the model properties in delegate, this is the syntax:

    model.<propertyName>



  • @literA2 Thanks again, that does indeed work!

    I'm not sure what I'm doing wrong, but I often have trouble figuring out these smaller details. I keep looking in the documentation, but I guess I keep looking in the wrong place.

    In any case, my complete solution to the original problem is, as per @literA2's suggestion, to use setContextProperty in main.cpp. The model is still owned by the modelManager in my case, but I expose the model to QML in main.cpp by calling a getter.

    main.cpp

    ModelManager modelManager;
    
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("myListModel", modelManager.myListModel());
    
    ...
    

    myListModel() returns a pointer to the MyListModel of the ModelManager.

    In my case, I can test that this works by having a ListView that displays the contents of the model like this. I'm using the default display role currently.

    ListView
    {
    id: testView
    width: 200
    height: 200
    x: 50
    y: 50
    model: myListModel
    
    delegate: Text {
    text: model.display
    }
    


  • @Obi-Wan i think you don't need to exposed your modelManager, you can omit that line.



  • @literA2 said in Access model owned by class in QML:

    @Obi-Wan i think you don't need to exposed your modelManager, you can omit that line.

    You are absolutely right I think, it is only there because I'm using for something else. I'll remove it here for clarity.


Log in to reply