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

955 Views Asked by At

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

1

There are 1 best solutions below

0
Kaien Yim On BEST ANSWER

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...