Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. how to distinguish between multiple C++ models?
Qt 6.11 is out! See what's new in the release blog

how to distinguish between multiple C++ models?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
13 Posts 4 Posters 1.1k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • mzimmersM mzimmers

    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?
                        }
                    }
                }
            }
        }
    }
    
    
    
    sierdzioS Offline
    sierdzioS Offline
    sierdzio
    Moderators
    wrote on last edited by
    #2

    @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 model or modelData to 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
        }
      }
    }
    

    (Z(:^

    mzimmersM 1 Reply Last reply
    1
    • sierdzioS sierdzio

      @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 model or modelData to 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
          }
        }
      }
      
      mzimmersM Offline
      mzimmersM Offline
      mzimmers
      wrote on last edited by mzimmers
      #3

      @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:

      1. list each zone
      2. for each zone, list its equipment items
      3. 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).equipmentList
      

      I 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.

      fcarneyF 1 Reply Last reply
      0
      • mzimmersM mzimmers

        @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:

        1. list each zone
        2. for each zone, list its equipment items
        3. 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).equipmentList
        

        I 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.

        fcarneyF Offline
        fcarneyF Offline
        fcarney
        wrote on last edited by fcarney
        #4

        @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
            }
        }
        

        C++ is a perfectly valid school of magic.

        mzimmersM 1 Reply Last reply
        1
        • fcarneyF fcarney

          @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
              }
          }
          
          mzimmersM Offline
          mzimmersM Offline
          mzimmers
          wrote on last edited by
          #5

          @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...

          fcarneyF 1 Reply Last reply
          0
          • mzimmersM mzimmers

            @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...

            fcarneyF Offline
            fcarneyF Offline
            fcarney
            wrote on last edited by
            #6

            @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?

            C++ is a perfectly valid school of magic.

            mzimmersM 1 Reply Last reply
            1
            • fcarneyF fcarney

              @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?

              mzimmersM Offline
              mzimmersM Offline
              mzimmers
              wrote on last edited by mzimmers
              #7

              @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?

              J.HilkJ 1 Reply Last reply
              1
              • mzimmersM mzimmers

                @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?

                J.HilkJ Offline
                J.HilkJ Offline
                J.Hilk
                Moderators
                wrote on last edited by
                #8

                @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 index literary :D !!!!
                The delegate gets a index property "injected" and you can access it. In your case. zoneDelegate should have access to it


                Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                Q: What's that?
                A: It's blue light.
                Q: What does it do?
                A: It turns blue.

                mzimmersM 1 Reply Last reply
                2
                • J.HilkJ J.Hilk

                  @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 index literary :D !!!!
                  The delegate gets a index property "injected" and you can access it. In your case. zoneDelegate should have access to it

                  mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by
                  #9

                  @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.HilkJ 1 Reply Last reply
                  0
                  • mzimmersM mzimmers

                    @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.HilkJ Offline
                    J.HilkJ Offline
                    J.Hilk
                    Moderators
                    wrote on last edited by
                    #10

                    @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
                                     }
                                }
                            }
                        }
                    }
                    

                    24f83b95-72c4-49b2-bb83-98d1b192ac75-image.png


                    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                    Q: What's that?
                    A: It's blue light.
                    Q: What does it do?
                    A: It turns blue.

                    mzimmersM 1 Reply Last reply
                    2
                    • J.HilkJ J.Hilk

                      @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
                                       }
                                  }
                              }
                          }
                      }
                      

                      24f83b95-72c4-49b2-bb83-98d1b192ac75-image.png

                      mzimmersM Offline
                      mzimmersM Offline
                      mzimmers
                      wrote on last edited by
                      #11

                      @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.HilkJ 1 Reply Last reply
                      0
                      • mzimmersM mzimmers

                        @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.HilkJ Offline
                        J.HilkJ Offline
                        J.Hilk
                        Moderators
                        wrote on last edited by J.Hilk
                        #12

                        @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


                        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                        Q: What's that?
                        A: It's blue light.
                        Q: What does it do?
                        A: It turns blue.

                        mzimmersM 1 Reply Last reply
                        1
                        • J.HilkJ J.Hilk

                          @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

                          mzimmersM Offline
                          mzimmersM Offline
                          mzimmers
                          wrote on last edited by mzimmers
                          #13

                          @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
                              : null
                          

                          If 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
                              : null
                          

                          EDIT 3:

                          I like this even better:

                          model: (zoneDelegate.zoneIndex >= 0 && zoneModel.listSize() > zoneDelegate.zoneIndex)
                              ? zoneModel.getZone(zoneDelegate.zoneIndex).equipmentList
                              : null
                          

                          Anyway, enough fun and games. Unless someone sees a problem with this, I'll go ahead and consider it solved. Thanks to everyone who assisted.

                          1 Reply Last reply
                          1
                          • mzimmersM mzimmers has marked this topic as solved on
                          • mzimmersM mzimmers has marked this topic as unsolved on
                          • mzimmersM mzimmers has marked this topic as solved on

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved