how to distinguish between multiple C++ models?
-
Hi all -
I'm trying to code a list within a list, that draws upon two models (both defined in C++). I'm having trouble figuring out how to distinguish between the models in my inner list. How can I identify which model I want to use here?
This is a simplified example; my real code is a bit more elaborate. Thanks...
// C++ typedef QList<QUuid> ZoneEquipmentList; class Zone { Q_GADGET ZoneEquipmentList m_equipmentList; public: Q_PROPERTY(ZoneEquipmentList equipmentList MEMBER m_equipmentList) ZoneEquipmentList equipmentList() const { return m_equipmentList; } ... } // QML ListView { id: infoScreen model: zoneModel // defined by me delegate: Rectangle { id: infoDelegate Column { Text { text: "zone ID is " + model.uuid } ListView { model: zoneModel.getZone(model.equipmentList) delegate: Column { Text { text: // how to distinguish between models here? } } } } } } -
@J-Hilk I guess I don't understand -- I tried this:
ListView { model: zoneModel delegate: Rectangle { id: zoneDelegate Column { Text { text: "zoneDelegate.index: " + zoneDelegate.index // undefined } ListView { model: zoneModel.getZone(zoneDelegate.index).equipmentList delegate: Column { Text { text: "equipment uuid: " + equipmentModel.getItem(modelData).uuid() } } } } } }and zoneDelegate.index comes back as undefined.
@mzimmers yeah, thats not a property in the normal sense. You'll have to actually "store" it locally to access it out of the scope:
Window { width: 640 height: 480 visible: true title: qsTr("Hello World") ListView{ id:view1 anchors.fill: parent model: 10 delegate: Item { id:view1Delegate property int indexPropagation: index height: 50 width: 640 ListView { id:view2 anchors.fill: parent model: ["Apples", "Bananas", "Oranges"] delegate: Label { height: contentHeight width: view2.width text: modelData + " " + view1Delegate.indexPropagation + " " + index } } } } }
-
Hi all -
I'm trying to code a list within a list, that draws upon two models (both defined in C++). I'm having trouble figuring out how to distinguish between the models in my inner list. How can I identify which model I want to use here?
This is a simplified example; my real code is a bit more elaborate. Thanks...
// C++ typedef QList<QUuid> ZoneEquipmentList; class Zone { Q_GADGET ZoneEquipmentList m_equipmentList; public: Q_PROPERTY(ZoneEquipmentList equipmentList MEMBER m_equipmentList) ZoneEquipmentList equipmentList() const { return m_equipmentList; } ... } // QML ListView { id: infoScreen model: zoneModel // defined by me delegate: Rectangle { id: infoDelegate Column { Text { text: "zone ID is " + model.uuid } ListView { model: zoneModel.getZone(model.equipmentList) delegate: Column { Text { text: // how to distinguish between models here? } } } } } }@mzimmers said in how to distinguish between multiple C++ models?:
It's been a while since I've done something like it, but I think the trick was:
- use
modelormodelDatato access the "current" (inner) model - when you need a property from "parent" model, declare it as a property in inner ListView
So:
ListView { model: zoneModel.getZone(model.equipmentList) property string parentProperty: model.someParentProp delegate: Column { Text { text: model.propertyFromInnerModel + parenProperty } } } - use
-
@mzimmers said in how to distinguish between multiple C++ models?:
It's been a while since I've done something like it, but I think the trick was:
- use
modelormodelDatato access the "current" (inner) model - when you need a property from "parent" model, declare it as a property in inner ListView
So:
ListView { model: zoneModel.getZone(model.equipmentList) property string parentProperty: model.someParentProp delegate: Column { Text { text: model.propertyFromInnerModel + parenProperty } } }@sierdzio doesn't seem to be working, at least not how I'm trying. The inner code still seems to be confused about which model to use.
The taxonomy is: the ZoneModel maintains a list of Zones; and each Zone has a list of Equipment item UUIDs. I'm trying to:
- list each zone
- for each zone, list its equipment items
- for each equipment item, list a few properties
I've further reduced the example:
ListView { id: infoScreen model: zoneModel delegate: ListView { model: zoneModel.getZone(model.equipmentList) // error on this line delegate: Text { text: "equipment name: " + model.name } } } }And I get a runtime error: TypeError: Cannot read property 'equipmentList' of undefined.
Shouldn't the model be something more like:
model: zoneModel.getZone(index).equipmentListI know this isn't right, because 1) it doesn't display anything, and 2) it crashes after a few seconds, but it seems closer to what I'm trying to use as the model.
- use
-
@sierdzio doesn't seem to be working, at least not how I'm trying. The inner code still seems to be confused about which model to use.
The taxonomy is: the ZoneModel maintains a list of Zones; and each Zone has a list of Equipment item UUIDs. I'm trying to:
- list each zone
- for each zone, list its equipment items
- for each equipment item, list a few properties
I've further reduced the example:
ListView { id: infoScreen model: zoneModel delegate: ListView { model: zoneModel.getZone(model.equipmentList) // error on this line delegate: Text { text: "equipment name: " + model.name } } } }And I get a runtime error: TypeError: Cannot read property 'equipmentList' of undefined.
Shouldn't the model be something more like:
model: zoneModel.getZone(index).equipmentListI know this isn't right, because 1) it doesn't display anything, and 2) it crashes after a few seconds, but it seems closer to what I'm trying to use as the model.
@mzimmers You can use attached properties for ListView. To get the model for the ListView for the current delegate then do ListView.view.model. You are also dealing with 3 different models by having a nested listview. The injected model of the first listview, the injected model of the second listview, and the model property of the nested listview. It would be better if the nested listview delegate looked like this:
delegate: Item { // injected model here ListView { // model of this listview is not occluded } } -
@mzimmers You can use attached properties for ListView. To get the model for the ListView for the current delegate then do ListView.view.model. You are also dealing with 3 different models by having a nested listview. The injected model of the first listview, the injected model of the second listview, and the model property of the nested listview. It would be better if the nested listview delegate looked like this:
delegate: Item { // injected model here ListView { // model of this listview is not occluded } } -
@fcarney I actually have a Rectangle as the delegate for my outer list; I just removed it from my posted code.
What does "injected model" mean exactly?
Thanks...
@mzimmers said in how to distinguish between multiple C++ models?:
What does "injected model" mean exactly?
The delegate gets the keyword "model" injected into its namespace doesn't it? So that the delegate can use the word "model" to refer to the model of the view?
-
@mzimmers said in how to distinguish between multiple C++ models?:
What does "injected model" mean exactly?
The delegate gets the keyword "model" injected into its namespace doesn't it? So that the delegate can use the word "model" to refer to the model of the view?
@fcarney OK, I see (just not really familiar with the term "injected" in Qt-land).
I've made a couple changes:
ListView { id: infoScreen model: zoneModel delegate: Rectangle { id: zoneDelegate Column { Text { text: "zone UUID: " + model.uuid } ListView { id: equipmentList model: zoneModel.getZone(1).equipmentList // ?? how to use index in getZone()? delegate: Column { id: equipmentDetails anchors.fill: parent Text { text: "equipment name: " + equipmentDetails.ListView.view.model } } } } } }This gets me the zone UUID in the inner ListView. Running it verifies the data is correct. Now, I need to use this UUID in a call to my equipment model in order to get the equipment details from the equipment list (via the equipment model).
Maybe I'm trying to do too much in QML, and I should add a routine to my Zone model to retrieve a equipment item (the whole item, not just its UUID)?EDIT: OK, I got most of it working; the missing ingredient was modelData:
ListView { id: equipmentList model: zoneModel.getZone(1).equipmentList delegate: Column { Text { text: "equipment name: " + equipmentModel.getItem(modelData).name() } } }Now...how can I replace that "1" with something to represent the current index for that iteration through the model?
-
@fcarney OK, I see (just not really familiar with the term "injected" in Qt-land).
I've made a couple changes:
ListView { id: infoScreen model: zoneModel delegate: Rectangle { id: zoneDelegate Column { Text { text: "zone UUID: " + model.uuid } ListView { id: equipmentList model: zoneModel.getZone(1).equipmentList // ?? how to use index in getZone()? delegate: Column { id: equipmentDetails anchors.fill: parent Text { text: "equipment name: " + equipmentDetails.ListView.view.model } } } } } }This gets me the zone UUID in the inner ListView. Running it verifies the data is correct. Now, I need to use this UUID in a call to my equipment model in order to get the equipment details from the equipment list (via the equipment model).
Maybe I'm trying to do too much in QML, and I should add a routine to my Zone model to retrieve a equipment item (the whole item, not just its UUID)?EDIT: OK, I got most of it working; the missing ingredient was modelData:
ListView { id: equipmentList model: zoneModel.getZone(1).equipmentList delegate: Column { Text { text: "equipment name: " + equipmentModel.getItem(modelData).name() } } }Now...how can I replace that "1" with something to represent the current index for that iteration through the model?
@mzimmers said in how to distinguish between multiple C++ models?:
Now...how can I replace that "1" with something to represent the current index for that iteration through the model?
via
indexliterary :D !!!!
The delegate gets a index property "injected" and you can access it. In your case.zoneDelegateshould have access to it -
@mzimmers said in how to distinguish between multiple C++ models?:
Now...how can I replace that "1" with something to represent the current index for that iteration through the model?
via
indexliterary :D !!!!
The delegate gets a index property "injected" and you can access it. In your case.zoneDelegateshould have access to it@J-Hilk I guess I don't understand -- I tried this:
ListView { model: zoneModel delegate: Rectangle { id: zoneDelegate Column { Text { text: "zoneDelegate.index: " + zoneDelegate.index // undefined } ListView { model: zoneModel.getZone(zoneDelegate.index).equipmentList delegate: Column { Text { text: "equipment uuid: " + equipmentModel.getItem(modelData).uuid() } } } } } }and zoneDelegate.index comes back as undefined.
-
@J-Hilk I guess I don't understand -- I tried this:
ListView { model: zoneModel delegate: Rectangle { id: zoneDelegate Column { Text { text: "zoneDelegate.index: " + zoneDelegate.index // undefined } ListView { model: zoneModel.getZone(zoneDelegate.index).equipmentList delegate: Column { Text { text: "equipment uuid: " + equipmentModel.getItem(modelData).uuid() } } } } } }and zoneDelegate.index comes back as undefined.
@mzimmers yeah, thats not a property in the normal sense. You'll have to actually "store" it locally to access it out of the scope:
Window { width: 640 height: 480 visible: true title: qsTr("Hello World") ListView{ id:view1 anchors.fill: parent model: 10 delegate: Item { id:view1Delegate property int indexPropagation: index height: 50 width: 640 ListView { id:view2 anchors.fill: parent model: ["Apples", "Bananas", "Oranges"] delegate: Label { height: contentHeight width: view2.width text: modelData + " " + view1Delegate.indexPropagation + " " + index } } } } }
-
@mzimmers yeah, thats not a property in the normal sense. You'll have to actually "store" it locally to access it out of the scope:
Window { width: 640 height: 480 visible: true title: qsTr("Hello World") ListView{ id:view1 anchors.fill: parent model: 10 delegate: Item { id:view1Delegate property int indexPropagation: index height: 50 width: 640 ListView { id:view2 anchors.fill: parent model: ["Apples", "Bananas", "Oranges"] delegate: Label { height: contentHeight width: view2.width text: modelData + " " + view1Delegate.indexPropagation + " " + index } } } } }
@J-Hilk partial success:
ListView { model: zoneModel delegate: Rectangle { id: zoneDelegate property int zoneIndex: index Column { Text { text: "zoneDelegate.index: " + zoneDelegate.zoneIndex // this works } ListView { // something in this causes crash model: zoneModel.getZone(zoneDelegate.zoneIndex).equipmentList delegate: Column { Text { text: "equipment uuid: " + equipmentModel.getItem(modelData).uuid() } } } } } }With this code, the app hangs for a few seconds then crashes (no reason given in console). I suspect the problem is in my use of that property in my model declaration:
model: zoneModel.getZone(zoneDelegate.zoneIndex).equipmentList -
@J-Hilk partial success:
ListView { model: zoneModel delegate: Rectangle { id: zoneDelegate property int zoneIndex: index Column { Text { text: "zoneDelegate.index: " + zoneDelegate.zoneIndex // this works } ListView { // something in this causes crash model: zoneModel.getZone(zoneDelegate.zoneIndex).equipmentList delegate: Column { Text { text: "equipment uuid: " + equipmentModel.getItem(modelData).uuid() } } } } } }With this code, the app hangs for a few seconds then crashes (no reason given in console). I suspect the problem is in my use of that property in my model declaration:
model: zoneModel.getZone(zoneDelegate.zoneIndex).equipmentList -
@mzimmers make your getZone function so that it catches invalid indexes. I had it happen, that the value was negative for some reason. Didn't happen always but caused problems non the less
@J-Hilk that’s easily enough done. What’s the cleanest way to make the model null if the index is bad?
EDIT:
This is kind of a hack, but here's my getZone():
Zone ZoneModel::getZone(int index) { Zone z = Zone(); // c'tor creates Zone with all empty elements do { if (index < 0) { qDebug() << "ZoneModel::getZone(): invalid index" << index << "requested."; continue; } if (m_list->size() <= index) { qDebug() << "ZoneModel::getZone(): requested index" << index << "exceeds list size."; continue; } z = m_list->getItem(index); } while (false); return z; }And my model check:
model: zoneModel.getZone(zoneDelegate.zoneIndex).name !== "" ? zoneModel.getZone(zoneDelegate.zoneIndex).equipmentList : nullIf there's no better way to do this, I suppose I should add a "valid" flag to my Zone class. Set to false by default upon construction; set to true whenever a Zone is created anywhere but getZone(). Thoughts?
Thanks…
EDIT 2:
I decided I liked this better:
model: (zoneModel.listSize() > zoneDelegate.zoneIndex) ? zoneModel.getZone(zoneDelegate.zoneIndex).equipmentList : nullEDIT 3:
I like this even better:
model: (zoneDelegate.zoneIndex >= 0 && zoneModel.listSize() > zoneDelegate.zoneIndex) ? zoneModel.getZone(zoneDelegate.zoneIndex).equipmentList : nullAnyway, enough fun and games. Unless someone sees a problem with this, I'll go ahead and consider it solved. Thanks to everyone who assisted.
-
M mzimmers has marked this topic as solved on
-
M mzimmers has marked this topic as unsolved on
-
M mzimmers has marked this topic as solved on