I have this class:
//main_model.hpp
#ifndef MAIN_MODEL_H
#define MAIN_MODEL_H
#include <QObject>
#include <QVariantMap>
class MainModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantMap map READ map NOTIFY mapChanged)
public:
MainModel();
const QVariantMap& map() const { return m_map; }
signals:
void mapChanged();
private:
QVariantMap m_map;
};
#endif // MAIN_MODEL_H
And in main_model.cpp:
#include "main_model.hpp"
MainModel::MainModel()
{
m_map.insert("KEY1", "VALUE1");
m_map.insert("KEY2", "VALUE2");
m_map.insert("KEY3", "VALUE3");
emit mapChanged();
}
I have registered the MainModel class as mainModel through the QML engine, then in main.qml
Window {
height: 640
width: 360
visible: true
ComboBox {
height: parent.height * 0.1
width: parent.width * 0.5
anchors.centerIn: parent
model: mainModel.map // This is not working
}
}
I would like to show in the ComboBox the values of the map -> ["VALUE1","VALUE2","VALUE3"], and when the ComboBox selection changes I would like to log which key was chosen. Is this possible?
ComboBox
really needs something a list such as QQmlListProperty
, QAbstractListModel
(including QML ListModel), or a QList
(e.g. QVariantList
). Because you're using a QVariantMap
it doesn't work because it is not list-like or array-like. QVariantMap
behaves like a JavaScript object, so a quick fix would be to convert the JavaScript object to an JavaScript array using one of the following: Object.values()
, Object.keys()
or Object.entries
. For example:
ComboBox {
height: parent.height * 0.1
width: parent.width * 0.5
anchors.centerIn: parent
// model: mainModel.map // This is not working
model: Object.values(mainModel.map)
}
I know you're instantiating MainModel and assigning it directly to the context property, but, in general, the constructor of a QObject component should also support a QObject* parent property, e.g.
class MainModel : public QObject
{
//...
public:
// MainModel();
MainModel(QObject* parent = nullptr);
//...
And the implementation, of course, should also do something with that parameter, e.g.
// MainModel::MainModel()
MainModel::MainModel(QObject* parent) : QObject(parent)
{
m_map.insert("KEY1", "VALUE1");
m_map.insert("KEY2", "VALUE2");
m_map.insert("KEY3", "VALUE3");
emit mapChanged();
}
Another quick fix would be to replace QVariantMap
with QVariantList
. In the following example, I also updated the Q_PROPERTY
to use the default getter by using MEMBER
instead of READ
thus reducing the need to implement a custom getter.
// MainModel.h
#ifndef MAIN_MODEL_H
#define MAIN_MODEL_H
#include <QObject>
#include <QVariantMap>
class MainModel : public QObject
{
Q_OBJECT
// Q_PROPERTY(QVariantMap map READ map NOTIFY mapChanged)
Q_PROPERTY(QVariantList list MEMBER m_list NOTIFY listChanged)
public:
MainModel(QObject* parent = nullptr);
// const QVariantMap& map() const { return m_map; }
signals:
void listChanged();
private:
// QVariantMap m_map;
QVariantList m_list;
};
#endif // MAIN_MODEL_H
// MainModel.cpp
#include "MainModel.h"
MainModel::MainModel(QObject* parent) : QObject(parent)
{
QVariantMap map;
map["key"] = "KEY1";
map["value"] = "VALUE1";
m_list.append(map);
map["key"] = "KEY2";
map["value"] = "VALUE2";
m_list.append(map);
map["key"] = "KEY3";
map["value"] = "VALUE3";
m_list.append(map);
emit listChanged();
}
// main.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
ComboBox {
height: parent.height * 0.1
width: parent.width * 0.5
anchors.centerIn: parent
model: mainModel.list
textRole: "key"
valueRole: "value"
}
}