Search code examples
qtcomboboxqmlqstringlistmodel

QML Error "modelData is not defined" when using Combobox with QStringList model


I'm new to Qt and QML. I want to show my list using combobox with the QStringList model. But, it doesn't work at all. Below is the related source code.

ListModelResourceManager.hpp

class ListModelResourceManager : public QObject {
    Q_OBJECT
    Q_PROPERTY(QStringList model MEMBER m_model NOTIFY modelChanged)
    QStringList m_model;
public:
    ListModelResourceManager(const QString& ctx_id, const QQmlApplicationEngine& engine,  QObject* parent = nullptr);
  public slots:
    void update();
  signals:
    void modelChanged();
};

main.cpp

...
ListModelResourceManager lmResourceManager("MODEL_ResourceManagerList", engine);
...
engine.load(QUrl(QStringLiteral("qrc:/viewmain.qml")));

viewmain.qml

ComboBox {
   id: idResourceList
   height: 30
   visible: true
   //model: ["First", "Second", "Third"] // IT WORKS well!!!
   model : MODEL_ResourceManagerList.model

   onFocusChanged: {
      MODEL_ResourceManagerList.update();
   }

   delegate: ItemDelegate {
      width: parent.width
      text: modelData
      font.weight: idResourceList.currentIndex === index ? Font.DemiBold : Font.Normal
      font.pixelSize: 30
      highlighted: idResourceList.highlightedIndex == index
      }

when using commented model definition ( model: ["First", "Second", "Third"] ) it works well.

please let me know what's wrong in my code part. thanks


Solution

  • I found my bug, so I replied to my answer by myself.

    To register model to view components, the registering object must be the model type class. In my case, my ListModelResourceManager is not model class. so need to use QStringListModel as a model class than link this QStringListModel object to QML Combobox components.

    I updated my working source here for someone who feel pain like me

    ListModelResourceManager.hpp (managing QStringListMoel)

    class ListModelResourceManager : public QObject {
        Q_OBJECT
        QStringListModel m_model;
    public:
        ListModelResourceManager(const QString& model_id, const QString& ctx_id, const QQmlApplicationEngine& engine,  QObject* parent = nullptr);
    };
    

    ListModelResourceManager.cpp (m_model is updated by callback function registered to native resource manager)

    ListModelResourceManager::ListModelResourceManager(const QString& model_id, const QString& ctx_id, const QQmlApplicationEngine& engine,  QObject* parent)
        : QObject(parent), m_model()
    {
        engine.rootContext()->setContextProperty(ctx_id, this);
        engine.rootContext()->setContextProperty(model_id, &m_model);
    
        rutResource::ResourceManager::getInstance().addResourceUpdatedListener([this](){
            auto resources = rutResource::ResourceManager::getInstance().resources();
            QStringList list;
            for (auto item : resources)
            {
                list.append(QString::fromUtf8(item.first.c_str()));
            }
            m_model.setStringList(list);
        });
    }
    

    main.cpp

    int main(int argc, char *argv[])
    {
    // ...
        ListModelResourceManager lmResourceManager("MODEL_Resources","ResourceManagerList", engine);
    // ...
    }
    

    view.qml

    // ...
       ComboBox {
           id : idResourceSelector          
           model : MODEL_Resources 
           textRole: "display"     
       }  
    // ...                         
    

    ps. I want to separate my native resource manager from QT interface, so I use the callback listener. If it is not your case, you can update your model by using other method like signal/slot etc...