I've got a struct with two fields, for example:
struct testStruct
{
Q_GADGET
Q_PROPERTY(QString text MEMBER m_text);
Q_PROPERTY(QString value MEMBER m_value);
public:
QString m_text;
QString m_value;
};
There is a QList<testStruct> m_testStructs
member of my "AppEngine" class exposed to QML via
Q_PROPERTY(QList<testStruct> testStructs READ testStructs NOTIFY testStructsChanged)
.
It is filled like that:
testStruct newStruct1, newStruct2;
newStruct1.m_text = "text1";
newStruct1.m_value = "value1";
newStruct2.m_text = "text2";
newStruct2.m_value = "value2";
m_testStructs << newStruct1 << newStruct2;
So I want to see "text" members in ComboBox list and use "value" members in further operations.
In fact QML ComboBox popup shows me the list of objects names when I set ComboBox's "textRole" property to "text" and "valueRole" to "value", but it does nothing for "currentText" or "currentValue" properties when I click the item, only "currentIndex" changes. Also "displayText" remains blank.
This is what I get in console when clicking those items:
qml: currentIndex: 0; currentText: ; currentValue: undefined
qml: currentIndex: 1; currentText: ; currentValue: undefined
So I see that ComboBox gets members of struct, but doesn't want to work with them. What should I do to make "currentText" and "currentValue" members of ComboBox work as they should?
Here are all the needed files:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "appengine.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(u"qrc:/qml_testComboBoxStruct/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
//exposing AppEngine class to QML
AppEngine appEngineObj;
QQmlContext *context = engine.rootContext();
context->setContextProperty("AppEngine", &appEngineObj);
engine.load(url);
return app.exec();
}
my custom class header AppEngine.h
#ifndef APPENGINE_H
#define APPENGINE_H
#include <QObject>
#include <QDebug>
struct testStruct
{
Q_GADGET
Q_PROPERTY(QString text MEMBER m_text);
Q_PROPERTY(QString value MEMBER m_value);
public:
QString m_text;
QString m_value;
};
Q_DECLARE_METATYPE(testStruct)
class AppEngine : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<testStruct> testStructs READ testStructs NOTIFY testStructsChanged);
public:
explicit AppEngine(QObject *parent = nullptr);
QList<testStruct> testStructs();
private:
QList<testStruct> m_testStructs;
signals:
void testStructsChanged();
};
#endif // APPENGINE_H
my custom class cpp file AppEngine.cpp
#include "appengine.h"
AppEngine::AppEngine(QObject *parent)
: QObject{parent}
{
testStruct newStruct1, newStruct2;
newStruct1.m_text = "text1";
newStruct1.m_value = "value1";
newStruct2.m_text = "text2";
newStruct2.m_value = "value2";
m_testStructs << newStruct1 << newStruct2;
qDebug() << "m_testStructs.length():" << m_testStructs.length();
}
QList<testStruct> AppEngine::testStructs()
{
qDebug() << "testStructs()";
return m_testStructs;
}
main.qml
import QtQuick
import QtQuick.Controls
Window {
width: 640
height: 480
visible: true
title: qsTr("C++ struct to QML ComboBox")
ComboBox
{
anchors.centerIn: parent
width: 180
height: 30
id: comboBoxID
textRole: "text"
valueRole: "value"
model: AppEngine.testStructs
onActivated:
{
console.log('currentIndex:', currentIndex, '; currentText:', currentText, ';currentValue:', currentValue);
}
}
}
As I checked in the main.qml
model property cant find and understand as you show it is undefined.
qml: currentIndex: 0; currentText: ; currentValue: undefined
qml: currentIndex: 1; currentText: ; currentValue: undefined
The model provides the set of data that is used to create the items in the view. Models can be created directly in QML using ListModel, ObjectModel, or provided by C++ model classes. If a C++ model class is used, it must be a subclass of QAbstractItemModel or a simple list.
For example, you can have this :
import QtQuick
import QtQuick.Controls
Window {
width: 640
height: 480
visible: true
title: qsTr("C++ struct to QML ComboBox")
ComboBox
{
id: comboBoxID
anchors.centerIn: parent
width: 180
height: 30
textRole: "text"
valueRole: "value"
model: ListModel {
id : model
ListElement { text: "text1" ; value : "value1" }
ListElement { text: "text2" ; value : "value2" }
ListElement { text: "text3" ; value : "value3" }
ListElement { text: "text4" ; value : "value4" }
}
onActivated:
{
console.log('currentIndex:', currentIndex, '; currentText:', currentText, '; currentValue:', currentValue);
}
}
}
Because you use QML ListModel if you want to define your model from C++ it must be a subclass of QAbstractItemModel or a simple list.
updated :
you need to use QStandardItemModel
which inherits from QAbstractItemModel
you cant inherit from the abstract interface because of that I use QStandardItemModel
in appengine.h:
#ifndef APPENGINE_H
#define APPENGINE_H
#include <QObject>
#include <QDebug>
#include <QStandardItemModel>
struct testStruct: public QStandardItemModel
{
Q_OBJECT
Q_PROPERTY(QString text MEMBER m_text);
Q_PROPERTY(QString value MEMBER m_value);
public:
QString m_text;
QString m_value;
};
Q_DECLARE_METATYPE(testStruct)
class AppEngine : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<testStruct *> testStructs READ testStructs NOTIFY testStructsChanged);
public:
explicit AppEngine(QObject *parent = nullptr);
QList<testStruct *> testStructs();
private:
QList<testStruct *> m_testStructs;
signals:
void testStructsChanged();
};
#endif // APPENGINE_H
In appengine.cpp
#include "appengine.h"
AppEngine::AppEngine(QObject *parent)
: QObject{parent}
{
testStruct *newStruct1 = new testStruct;
testStruct *newStruct2 = new testStruct;
newStruct1->m_text = "text1";
newStruct1->m_value = "value1";
newStruct2->m_text = "text2";
newStruct2->m_value = "value2";
m_testStructs << newStruct1 << newStruct2;
qDebug() << "m_testStructs.length():" << m_testStructs.length();
}
QList<testStruct *> AppEngine::testStructs()
{
qDebug() << "testStructs()";
return m_testStructs;
}