Best Practice to Add Dynamic QML from C++ data
-
@Placeable What do you mean by "formatted textfield setup" ?
@p3c0 said in Best Practice to Add Dynamic QML from C++ data:
@Placeable What do you mean by "formatted textfield setup" ?
In CPP I want to create a set of Texts to be used in QML - I read data from a JSON file and need to create Texts for QML dynamically. All data is stored on the CPP side so let's say I need to create a view with 3 Texts and another with 0 Texts. That is what I am struggling to do.
So I am wondering if it is possible to create these Texts in CPP (Whatever their CPP variant might be, I dunno) and then return this to be populated in said QML view by changing the QAbstractListModel class somehow.
-
@Placeable Do you mean something like dynamic object creation in QML ?
And in your case you want the QML component's code(Text
) will come from CPP ? -
@Placeable Do you mean something like dynamic object creation in QML ?
And in your case you want the QML component's code(Text
) will come from CPP ?@p3c0
Exactly so, dynamically. Basically I want to setup these Texts on the CPP side (Font size, formatting as such etc) and let QML now: Hey here is a Text for you to use, have fun! Oh by the way here's another Text to use for this ListItem. But that ListItem over there you will get no Text to use at all! Hah!So a ListItem could have a variable amount of Texts that I also need to somehow tell my View Delegate.
-
@Placeable I have done something similar my project here. So what that particular code does is it creates a
QQuickItem
from a base QML template as shown here. Then sets some color and font on it. So you can try to do something similar. But rememberQQmlComponent
requiresQQmlEngine
. This is the same with which you must have loaded the QML initially. Also remember that dynamicQQuickItem
also requires a visual parent which is set using setParent. -
@Placeable I have done something similar my project here. So what that particular code does is it creates a
QQuickItem
from a base QML template as shown here. Then sets some color and font on it. So you can try to do something similar. But rememberQQmlComponent
requiresQQmlEngine
. This is the same with which you must have loaded the QML initially. Also remember that dynamicQQuickItem
also requires a visual parent which is set using setParent.@p3c0 This is great, I like how to create QML from CPP. I came up with a different solution though which I think works but not sure if it is "best practice" - I'd like to experiment the way you did it as well.
Here's how I have done it now to create "dynamic" Texts in QML from CPP data:
In my QAbstractListModel data function I have this field that returns a QVariant:
case TextData: return QVariant::fromValue( someData.textList() ); break;
The implementation of that returns a QList of QObject:
QList<QObject*> SomeData::textList() const { return mTextList; }
I can populate this QList with my TextData class that derives QObject
TextData.cpp:
class TextData : public QObject { Q_OBJECT Q_PROPERTY(QString text READ testString WRITE setTestString NOTIFY testStringChanged) public: explicit TextData(QObject *parent = 0); QString testString() const; void setTestString(const QString &testString); signals: void testStringChanged(QString); private: QString mTestString; };
Then in QML I can do something like this now to create QML Texts and populate them from the CPP data:
Component.onCompleted: { var arr = model.textData; var component = Qt.createComponent("SomeTextLayout.qml"); for ( var i = 0; i < arr.length; i++ ) { var txtObject = arr[i]; var txtQml = component.createObject(someParentId); txtQml.text = txtObject.text; ... //Etc fill in more props from the txtObject } }
Again how this is performance wise I am not sure I am inclined to do the QML markup on the CPP side as well.
I'll mark this topic as Solved as I think there is a lot of great input here that would help anyone else in the future.Thanks everyone!
-
@Placeable Beware of Component.onCompleted.
The order of running the onCompleted handlers is undefined.
Due to this it could be possible that your initialized components may be not be available when required. May be create them when you require them.
-
@Placeable Beware of Component.onCompleted.
The order of running the onCompleted handlers is undefined.
Due to this it could be possible that your initialized components may be not be available when required. May be create them when you require them.
-
If you find no issues then continue. Just a warning if you find some odd behavior during your implementaion. In some of my cases I found that onCompleted is not the most reliable place for initialization of components. Sometimes it triggered earlier causing problems to the objects which were intialized in it and which were dependent on others.
-
If you find no issues then continue. Just a warning if you find some odd behavior during your implementaion. In some of my cases I found that onCompleted is not the most reliable place for initialization of components. Sometimes it triggered earlier causing problems to the objects which were intialized in it and which were dependent on others.
-
Haven't tried it, but I'd do something along the lines of:
ApplicationWindow { visible: true width: 640 height: 480 title: "Testing Model" ListView { model: testModel delegate: Rectangle { height: 25 width: 100 Text { id: tmText text: modelData.text anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom } Text { text: modelData.desctiption anchors.left: tmText.right anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom } } } }
Since this was something new from me and the issue popped up again after a while
I prepared a small wiki article that summarises the technique