View Full Version : property binding in a repeater
sedi
22nd March 2015, 10:10
Hi,
I have an item with 12 text fields, laid out as a grid and produced with a repeater.
Now I want to make bindings to one property each (line 29). How can I do that elegantly?
I don't even know which words to use for a google search on this...
I can imagine it might be possible with some kind of list in the property section?
Here's a condensed code that should clarify what I mean:
import QtQuick 2.2
import QtQuick.Controls 1.1
Item {
id: personButtonBasis
property string data00Text: ""
property string data01Text: ""
property string data02Text: ""
property string data03Text: ""
property string data04Text: ""
property string data05Text: ""
property string data06Text: ""
property string data07Text: ""
property string data08Text: ""
property string data09Text: ""
property string data10Text: ""
property string data11Text: ""
Grid {
id: dataTextGrid
columns: 3
Repeater {
id: dataFieldRepeater
model:12
Text {
text: ???????????
}
}
}
I tried in vain to "compose" the property name as in this (non-working) example (located starting from line 29):
Binding {
target: personButtonBasis;
property: (index<10)? "data0%1Text".arg(index) : "data%1Text".arg(index)
value: text
}
It might well be a very stupid question, as I am still very new to the QML world.
joko
23rd March 2015, 08:54
I think you need to implement it using ListModel
Item {
id: personButtonBasis
ListModel {
id: buttonModel
ListElement {
text: "Button 1"
}
ListElement {
text: "Button 2"
}
ListElement {
text: "Button 3"
}
ListElement {
text: "Button 4"
}
}
Grid {
id: dataTextGrid
columns: 3
Repeater {
id: dataFieldRepeater
model: buttonModel
Text {
text: model.text
}
}
}
}
anda_skoa
23rd March 2015, 09:11
What you would usually do in such a situation is to have a model instead of all these string properties.
In the easiest case the model would just be a list of strings
Item {
property var texts: [ "a", "b", c" ]
Repeater {
model: parent.texts
Text {
text: modelData
}
}
}
Cheers,
_
sedi
1st April 2015, 10:41
Thanks, anda_skoa!
That's exactly what I did - and it works! I have a rather complex model with several lists in it and it was not easy to get it done, but here are a few details for others with the same problem. This is not a compileable example (too big), it may have been shortened too much and may contain simplification mistakes - but it might perhaps be able to shorten the solution finding process of others anyway.
I need several buttons, each with several data fields on it. The latter are defined here:
class DataFieldContent: public QObject
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
signals:
void textChanged();
void colorChanged();
public:
[...]
//getters
QString text();
QColor color();
//setters
void setText(QString text);
void setColor(QColor color);
};
All my data fields are organized in a C++ class "Content":
class Content: public QObject
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<DataFieldContent>dataFieldContents READ dataFieldContents NOTIFY dataFieldContentsChanged)
signals:
void dataFieldContentsChanged();
public:
[...]
QQmlListProperty<DataFieldContent> dataFieldContents() { return
QQmlListProperty<DataFieldContent> (this,
0,
&appendDataFieldContent,
&dataFieldContentsCount,
&dataFieldContentAt,
&dataFieldContentsClear);
}
static void appendDataFieldContent(QQmlListProperty<DataFieldContent> *list, DataFieldContent *p);
static int dataFieldContentsCount(QQmlListProperty<DataFieldContent> *list);
static DataFieldContent* dataFieldContentAt(QQmlListProperty<DataFieldContent> *list, int i);
static void dataFieldContentsClear(QQmlListProperty<DataFieldContent> *list);
protected:
QList<DataFieldContent*>m_dataFieldContents;
As I need a bunch of those Buttons, there is also a GroupContent, basically a List of Contents (Note that QList does not derive from QObject, you can't "just use" it).
class GroupContent: public QObject
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<Content> contents READ contents NOTIFY contentsChanged)
signals:
void contentsChanged();
public slots:
void contentsChangedSlot();
public:
[...]
QQmlListProperty <Content> contents();
static void appendContent(QQmlListProperty<Content> *list, Content *p);
static int contentsCount(QQmlListProperty<Content>*list);
static Content* contentAt(QQmlListProperty<Content> *list, int i);
static void contentsClear(QQmlListProperty<Content> *list);
void addContent(Content* p) { m_Contents.append(p);}
protected:
QList<Content*> m_Contents;
};
On the QML side we need a display: MyButton.qml:
Item {
id: ButtonBasis
property var dataFields;
Grid {
[...]
Repeater {
id: dataFieldRepeater
model: ButtonBasis.dataFields
Text {
text: dataFieldRepeater.model[index].text
color: dataFieldRepeater.model[index].color
[...]
}
}
}
}
And all that is linked together in main.qml:
Repeater {
id: contentRepeater
model: groupContent.contents
delegate: MyButton {
dataFields: contentRepeater.model[index].dataFieldContents
[...]
}
}
Don't forget to register your classes to QML (e.g. in main.cpp) by:
qmlRegisterType<DataFieldContent>("de.yourdomain.whatsoever.whatsoever",2,0,"DataFieldContent");
qmlRegisterType<Content>("de.yourdomain.whatsoever.whatsoever",2,0,"Content");
qmlRegisterType<GroupContent>("de.yourdomain.whatsoever.whatsoever",2,0,"GroupContent");
anda_skoa
1st April 2015, 14:10
Inside a delegate you can always address the current data entry like this
model.property
E.g. in your case
text: model.text
color: model.color
Cheers,
_
sedi
1st April 2015, 23:31
You are right, of course. Normally that should be the easier solution. I have, although, tried that in vain before - probably the problem was my use of nested delegates - so "model" had to be specifically addressed.
anda_skoa
2nd April 2015, 07:45
In such a case I would suggest keeping the data locally referencable instead
delegate: Item {
id: delegateRoot
readonly property text: model.text
Text {
text: delegateRoot.text // or here also: parent.text
}
}
That way you can potentially use the delegate in other views, referencing the model through a named view binds it to that specific view instance (can't even rename the view without breaking the delegate!)
Cheers,
_
Powered by vBulletin® Version 4.2.5 Copyright © 2024 vBulletin Solutions Inc. All rights reserved.