Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. custom model isn't completely working
Forum Updated to NodeBB v4.3 + New Features

custom model isn't completely working

Scheduled Pinned Locked Moved Solved General and Desktop
30 Posts 5 Posters 3.4k Views 1 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

    @JoeCFD hmm...I think you're on to something.

    I created a setList() function (also patterned after the example) that contains those calls:

    void EquipmentModel::setList(EquipmentList *list)
    {
        beginResetModel();
        if (m_list != nullptr) {
            m_list->disconnect(this);
        }
    
        m_list = list;
    
        if (m_list != nullptr) {
            connect(m_list, &EquipmentList::preItemAppended, this, [=]() {
                const int index = m_list->equipment().size();
                beginInsertRows(QModelIndex(), index, index);
            });
            connect(m_list, &EquipmentList::postItemAppended, this, [=]() {
                endInsertRows();
            });
    
            connect(m_list, &EquipmentList::preItemRemoved, this, [=](int index) {
                beginRemoveRows(QModelIndex(), index, index);
            });
            connect(m_list, &EquipmentList::postItemRemoved, this, [=]() {
                endRemoveRows();
            });
        }
        endResetModel();
    }
    

    But...I never call it. I can try to modify my setData() to use it, though it will be tricky, as my list is a QObject, so I can't copy it. What do you think?

    EDIT:

    I modified this portion of my setData() as follows; still not getting the changes in the displays:

    beginResetModel();
    if (m_list->setItemAt(index.row(), item)) {
        qDebug() <<  __PRETTY_FUNCTION__ << "setItemAt() returned successfully; role is" << role;
        emit dataChanged(index, index, QVector<int>() << role);
        rc = true;
    } else {
        qWarning() << __PRETTY_FUNCTION__ << "error from setItemAt.";
    }
    endResetModel();
    

    I could move the begin/endResetModel() calls to the setItemAt() function, but I think the results would be the same, right?

    JoeCFDJ Offline
    JoeCFDJ Offline
    JoeCFD
    wrote on last edited by
    #15

    @mzimmers
    https://doc.qt.io/qt-6/qabstractitemmodel.html#beginResetModel
    When a model is reset it means that any previous data reported from the model is now invalid and has to be queried for again. This also means that the current item and any selected items will become invalid.

    When a model radically changes its data it can sometimes be easier to just call this function rather than emit dataChanged() to inform other components when the underlying data source, or its structure, has changed.

    You must call this function before resetting any internal data structures in your model or proxy model.

    mzimmersM 1 Reply Last reply
    0
    • JoeCFDJ JoeCFD

      @mzimmers
      https://doc.qt.io/qt-6/qabstractitemmodel.html#beginResetModel
      When a model is reset it means that any previous data reported from the model is now invalid and has to be queried for again. This also means that the current item and any selected items will become invalid.

      When a model radically changes its data it can sometimes be easier to just call this function rather than emit dataChanged() to inform other components when the underlying data source, or its structure, has changed.

      You must call this function before resetting any internal data structures in your model or proxy model.

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

      @JoeCFD it's as though the QML property that reflects the state just isn't getting the message to update. I wonder if there's something wrong with how I'm setting that property:

      Rectangle {
          id: fakeSwitch
          height: 30; width: 30
          property bool switchState: equipmentModel.getEquipmentItem(pumpUuid).powerState // does this look OK?
          color: switchState ? 'green' : 'gray'
          MouseArea {
              anchors.fill: parent
              onClicked: {
                  fakeSwitch.switchState = !fakeSwitch.switchState
                  equipmentModel.sendSwitchChange(pumpUuid, fakeSwitch.switchState)
              }
          }
      }
      
      JonBJ mzimmersM 2 Replies Last reply
      0
      • mzimmersM mzimmers

        @JoeCFD it's as though the QML property that reflects the state just isn't getting the message to update. I wonder if there's something wrong with how I'm setting that property:

        Rectangle {
            id: fakeSwitch
            height: 30; width: 30
            property bool switchState: equipmentModel.getEquipmentItem(pumpUuid).powerState // does this look OK?
            color: switchState ? 'green' : 'gray'
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    fakeSwitch.switchState = !fakeSwitch.switchState
                    equipmentModel.sendSwitchChange(pumpUuid, fakeSwitch.switchState)
                }
            }
        }
        
        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by JonB
        #17

        @mzimmers said in custom model isn't completely working:

        property bool switchState: equipmentModel.getEquipmentItem(pumpUuid).powerState // does this look OK?

        One thing. Your C++ code shows this is not a bool property, you test/set powerState() against Equipment::POWER_OFF/POWER_ON. Do these values convert correctly to bool?

        mzimmersM 1 Reply Last reply
        0
        • mzimmersM mzimmers

          @JoeCFD it's as though the QML property that reflects the state just isn't getting the message to update. I wonder if there's something wrong with how I'm setting that property:

          Rectangle {
              id: fakeSwitch
              height: 30; width: 30
              property bool switchState: equipmentModel.getEquipmentItem(pumpUuid).powerState // does this look OK?
              color: switchState ? 'green' : 'gray'
              MouseArea {
                  anchors.fill: parent
                  onClicked: {
                      fakeSwitch.switchState = !fakeSwitch.switchState
                      equipmentModel.sendSwitchChange(pumpUuid, fakeSwitch.switchState)
                  }
              }
          }
          
          mzimmersM Offline
          mzimmersM Offline
          mzimmers
          wrote on last edited by
          #18

          Another data point in this little mystery: I have 3 locations in my GUI that show the value of this model element. Two are in ordinary screens, and they're not updating correctly. The third is in a drawer, and it's always correct. The Switch code is virtually identical. Does the act of opening a drawer force an update to its contents? Is that why that one is always right?

          JoeCFDJ J.HilkJ 2 Replies Last reply
          0
          • JonBJ JonB

            @mzimmers said in custom model isn't completely working:

            property bool switchState: equipmentModel.getEquipmentItem(pumpUuid).powerState // does this look OK?

            One thing. Your C++ code shows this is not a bool property, you test/set powerState() against Equipment::POWER_OFF/POWER_ON. Do these values convert correctly to bool?

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

            @JonB I think it is. I started using that FakeSwitch because I couldn't tell whether the real Switch was self-updating, and giving me a red herring. Here's the code from the real Switch, and its behavior is essentially the same (nothing in the custom switch affects this issue):

            Switch_custom {
                id: cardSwitch
                visible: card.switchable
                checked: equipmentModel.getEquipmentItem(uuid).powerState === 1
                Layout.alignment: Qt.AlignRight
                onClicked: {
                    console.log("EquipmentCard.qml: switch clicked; value is " + cardSwitch.checked)
                    equipmentModel.sendSwitchChange(card.uuid, cardSwitch.checked)
                }
            }
            
            
            1 Reply Last reply
            0
            • mzimmersM mzimmers

              Another data point in this little mystery: I have 3 locations in my GUI that show the value of this model element. Two are in ordinary screens, and they're not updating correctly. The third is in a drawer, and it's always correct. The Switch code is virtually identical. Does the act of opening a drawer force an update to its contents? Is that why that one is always right?

              JoeCFDJ Offline
              JoeCFDJ Offline
              JoeCFD
              wrote on last edited by JoeCFD
              #20

              @mzimmers What is the role type of drawer? I guess there is a default role.

              mzimmersM 1 Reply Last reply
              0
              • JoeCFDJ JoeCFD

                @mzimmers What is the role type of drawer? I guess there is a default role.

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

                @JoeCFD I don't assign any role to anything in the drawer. I'm not sure how I'd even do that as it relates to the Switch it contains.

                1 Reply Last reply
                0
                • mzimmersM mzimmers

                  Another data point in this little mystery: I have 3 locations in my GUI that show the value of this model element. Two are in ordinary screens, and they're not updating correctly. The third is in a drawer, and it's always correct. The Switch code is virtually identical. Does the act of opening a drawer force an update to its contents? Is that why that one is always right?

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

                  @mzimmers said in custom model isn't completely working:

                  Does the act of opening a drawer force an update to its contents?

                  possibly that opening the drawer recreates the drawer content, forcing a reload of the data each time its opened


                  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
                  0
                  • J.HilkJ J.Hilk

                    @mzimmers said in custom model isn't completely working:

                    Does the act of opening a drawer force an update to its contents?

                    possibly that opening the drawer recreates the drawer content, forcing a reload of the data each time its opened

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

                    @J-Hilk well, in a sense, that's good news -- it would mean that my model isn't properly signaling changes at all, so at least the problem is consistent.

                    This is so weird -- it's almost as though the Switches on the different screens are independent of each other. Everything in the model seems to be working, from messaging the server, to accepting the response and (seemingly) sending the appropriate signals to QML.

                    I know this idea is a cheat, and I wouldn't want to use it in production, but...is there a way to force a QML component to update every time it becomes visible?

                    JoeCFDJ 1 Reply Last reply
                    0
                    • mzimmersM mzimmers

                      @J-Hilk well, in a sense, that's good news -- it would mean that my model isn't properly signaling changes at all, so at least the problem is consistent.

                      This is so weird -- it's almost as though the Switches on the different screens are independent of each other. Everything in the model seems to be working, from messaging the server, to accepting the response and (seemingly) sending the appropriate signals to QML.

                      I know this idea is a cheat, and I wouldn't want to use it in production, but...is there a way to force a QML component to update every time it becomes visible?

                      JoeCFDJ Offline
                      JoeCFDJ Offline
                      JoeCFD
                      wrote on last edited by JoeCFD
                      #24

                      @mzimmers

                       onVisibleChanged: {
                            console.log( " visible =", visible )
                            //do update if visible is true 
                       }
                      
                      mzimmersM 1 Reply Last reply
                      0
                      • JoeCFDJ JoeCFD

                        @mzimmers

                         onVisibleChanged: {
                              console.log( " visible =", visible )
                              //do update if visible is true 
                         }
                        
                        mzimmersM Offline
                        mzimmersM Offline
                        mzimmers
                        wrote on last edited by
                        #25

                        @JoeCFD the Creator doesn't like the "do update" construct; am I supposed to replace update with something?

                        JoeCFDJ 1 Reply Last reply
                        0
                        • mzimmersM mzimmers

                          @JoeCFD the Creator doesn't like the "do update" construct; am I supposed to replace update with something?

                          JoeCFDJ Offline
                          JoeCFDJ Offline
                          JoeCFD
                          wrote on last edited by
                          #26

                          @mzimmers these are only texts. You do your update there.

                          mzimmersM 1 Reply Last reply
                          0
                          • JoeCFDJ JoeCFD

                            @mzimmers these are only texts. You do your update there.

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

                            @JoeCFD OK, but what is the command to force the update?

                            Here's what's happening: in my model, I make the change at the appropriate time:

                            if (m_list->setItemAt(i, itemFromList)) {
                                QModelIndex qmi = index(i, 0, QModelIndex());
                                setData(qmi, itemFromList.powerState(), StateRole);
                                qDebug() << __PRETTY_FUNCTION__ << "changed powerState to" << itemFromList.powerState();
                            }
                            

                            And in a qml screen, I have this code:

                            Text { text: "equipmentModel.getEquipmentItem(pumpUuid).powerState is " + equipmentModel.getEquipmentItem(pumpUuid).powerState }
                            

                            This line is NOT reflecting the change made above. Somewhere there's a disconnect between the change, and the QML, but it seems like the model is doing everything correctly.

                            JoeCFDJ 1 Reply Last reply
                            0
                            • mzimmersM mzimmers

                              @JoeCFD OK, but what is the command to force the update?

                              Here's what's happening: in my model, I make the change at the appropriate time:

                              if (m_list->setItemAt(i, itemFromList)) {
                                  QModelIndex qmi = index(i, 0, QModelIndex());
                                  setData(qmi, itemFromList.powerState(), StateRole);
                                  qDebug() << __PRETTY_FUNCTION__ << "changed powerState to" << itemFromList.powerState();
                              }
                              

                              And in a qml screen, I have this code:

                              Text { text: "equipmentModel.getEquipmentItem(pumpUuid).powerState is " + equipmentModel.getEquipmentItem(pumpUuid).powerState }
                              

                              This line is NOT reflecting the change made above. Somewhere there's a disconnect between the change, and the QML, but it seems like the model is doing everything correctly.

                              JoeCFDJ Offline
                              JoeCFDJ Offline
                              JoeCFD
                              wrote on last edited by
                              #28

                              @mzimmers in my code above you can print out the data value. If it is right, set it. If not, you have to find out the reason.

                              mzimmersM 1 Reply Last reply
                              0
                              • JoeCFDJ JoeCFD

                                @mzimmers in my code above you can print out the data value. If it is right, set it. If not, you have to find out the reason.

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

                                @JoeCFD oh, OK, I got it.

                                Text { text: "equipmentModel.getEquipmentItem(pumpUuid).powerState is " + equipmentModel.getEquipmentItem(pumpUuid).powerState }
                                
                                Switch_custom {
                                    id: sw
                                    checked: equipmentModel.getEquipmentItem(pumpUuid).powerState === 1
                                    onClicked: {
                                        if (switchState === 1) {
                                            switchState = 0;
                                        } else {
                                            switchState = 1;
                                        }
                                        equipmentModel.sendSwitchChange(pumpUuid, switchState)
                                        console.log("Infoscreen.qml: new switch state is " + switchState)
                                    }
                                    onVisibleChanged: {
                                        console.log( "InfoScreen: Switch_custom visible =", visible)
                                        if (visible) {
                                            checked = equipmentModel.getEquipmentItem(pumpUuid).powerState === 1
                                        }
                                    }
                                }
                                

                                The forced update to the checked property of the Switch is working, so the powerState value is good. But the line of text above it (which should reflect the same value) still shows the old value of powerState.

                                It almost seems that my equipmentItem (the class that the list is composed of) needs to emit a signal when something changes, but my equipmentItem is just a Q_GADGET, so it can't emit signals. In the example, the list item is just a struct, so it's obviously not emitting a signal.

                                Aargh...

                                mzimmersM 1 Reply Last reply
                                0
                                • mzimmersM mzimmers

                                  @JoeCFD oh, OK, I got it.

                                  Text { text: "equipmentModel.getEquipmentItem(pumpUuid).powerState is " + equipmentModel.getEquipmentItem(pumpUuid).powerState }
                                  
                                  Switch_custom {
                                      id: sw
                                      checked: equipmentModel.getEquipmentItem(pumpUuid).powerState === 1
                                      onClicked: {
                                          if (switchState === 1) {
                                              switchState = 0;
                                          } else {
                                              switchState = 1;
                                          }
                                          equipmentModel.sendSwitchChange(pumpUuid, switchState)
                                          console.log("Infoscreen.qml: new switch state is " + switchState)
                                      }
                                      onVisibleChanged: {
                                          console.log( "InfoScreen: Switch_custom visible =", visible)
                                          if (visible) {
                                              checked = equipmentModel.getEquipmentItem(pumpUuid).powerState === 1
                                          }
                                      }
                                  }
                                  

                                  The forced update to the checked property of the Switch is working, so the powerState value is good. But the line of text above it (which should reflect the same value) still shows the old value of powerState.

                                  It almost seems that my equipmentItem (the class that the list is composed of) needs to emit a signal when something changes, but my equipmentItem is just a Q_GADGET, so it can't emit signals. In the example, the list item is just a struct, so it's obviously not emitting a signal.

                                  Aargh...

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

                                  Hi all -

                                  Thanks for all the assistance. I'm going to close this topic, even though it's not solved, because I've come to realize that my model is overly complicated, and it make it difficult for me to explain here (there are parts of it that I still don't understand).

                                  So, I'm going to make the following changes to my model:

                                  • use an internal QList instead of using a separate class (currently EquipmentList) for my data list.

                                  • replace the EquipmentItem class with a struct, and eliminate all the now-unnecessary getters and setters.

                                  Hopefully these changes will make it a lot easier to follow what's happening. If I run into trouble, I'll start a new topic...thanks again.

                                  1 Reply Last reply
                                  0
                                  • 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