Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Unsolved Inconsistency between model and view while updating QSqlTableModel cell

    QML and Qt Quick
    qml model-view modelview model view prog
    4
    9
    598
    Loading More Posts
    • 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.
    • Ahti
      Ahti last edited by Ahti

      Background:

      I have a model that stores list of users with their profile information. The users are shown on main.qml and their profile on profile.qml.

      I am using ListView ( Not TableView ) to display list of users from QSqlTableModel and to display profile I use TableView with the same underlying model.

      Problem:

      When I try to update a user profile by editing their info. and hiting save button the model seems to get updated in the background but the view doesn't. To let the view show the change I have to restart my application.

      Code:

      main.qml:

       // this qml shows list of users from model
      
      StackView {
          id: home
          anchors.fill: parent
          padding: 0
          property var model: null
      
          initialItem: Pane {
              ColumnLayout {
                      id: body
      
                      ListView {
                          id: view
                          currentIndex: -1
                          height: body.height
                          width: body.width                        
      
                          delegate: SwipeDelegate {
                                  id: content
                                  width: parent.width
                                  height: 50
                                  text: model.name
                                  swipe.onCompleted: {
                                      if (swipe.position > 0){
                                           home.model = model
                                           home.pop()										 
                                           home.push("Profile.qml")
      				}
                                      swipe.close()
                                  }
      
                                  swipe.left: Label {
                                      text: qsTr("Profile")
                                      color: "white"
                                      verticalAlignment: Label.AlignVCenter
                                      padding: 12
                                      height: parent.height
                                      anchors.left: parent.left
                                      opacity: 2 * content.swipe.position
                                  }
                          }
      
                          model: UserModel { id: user_model }
      
                          ScrollIndicator.vertical: ScrollIndicator {}
                      }
                  }
      		}				
      	}
      

      profile.qml:

          // this qml shows user profile which can be edited and submitted with save button
      
          ColumnLayout {
                  id: info
                  spacing: 10
      			
                  RowLayout {
                      id: phone_g
                      width: parent.width
      
                      TextField {
                          id: phone
                          text: home.model.phone
                          font.pixelSize: 13                    
                      }
                  }
                  RowLayout {
                      id: address_g
                      width: parent.width
      
                      TextField {
                          id: address
                          text: home.model.address
                          font.pixelSize: 13
                      }
                  }
                  RowLayout {
                      id: save_l
                      width: parent.width
      
                      Button {
                          id: save_btn
                          text: "save"
                          onClicked { 
                                // this is where the model is updated and both the calls to setData return true
                               user_model.setData(user_model.index(home.model.index, 2), address.text)
                               user_model.setData(user_model.index(home.model.index, 3), phone.text)
                          }
                      }
                  }
          }	
      

      usermodel.cpp

      // this is how I manage to show list of users with ListView from QSqlModelTable ( which usually uses TableView instead of ListView )
      QVariant UserModel::data(const QModelIndex &index, int role) const{
          QVariant value;
          if (index.isValid()) {
              if (role < Qt::UserRole)
                  value = QSqlQueryModel::data(index, role);
              else {
                  int columnIdx = role - Qt::UserRole - 1;
                  QModelIndex modelIndex = this->index(index.row(), columnIdx);
                  value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole);
              }
          }
          return value;
      }
      
      QHash<int, QByteArray> UserModel::roleNames() const{
          QHash<int, QByteArray> roles;
          for (int i = 0; i < record().count(); i ++) {
              roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8());
          }
          return roles;
      }
      
      1 Reply Last reply Reply Quote 0
      • GrecKo
        GrecKo Qt Champions 2018 last edited by

        From what I understood, you are mapping custom roles in the first column to other source columns.
        When you are calling setData, you call it with an index whose column is after the first one.
        The base model will then call dataChanged(index, index, displayRole) in your case.
        However the ListView simply ignores those signals because it only cares about index in the first column. It has no way of knowing the data pointed by your roles in your first column have changed.

        What you could do is connect to the dataChanged signal in your model and do the reverse mapping, eg.: if dataChanged is called on the column 2, emit a dataChanged on column 0 with the adress role. Be carefull to reemit dataChanged only when needed to avoid infinite loops.

        Ahti 2 Replies Last reply Reply Quote 3
        • Ahti
          Ahti @GrecKo last edited by

          This post is deleted!
          1 Reply Last reply Reply Quote 0
          • Ahti
            Ahti @GrecKo last edited by

            This post is deleted!
            1 Reply Last reply Reply Quote 0
            • S
              sush123 last edited by

              Hi Ahti,

              Please have a look at https://doc.qt.io/qt-5/qabstractitemmodel.html#dataChanged

              Ahti 1 Reply Last reply Reply Quote 2
              • Ahti
                Ahti @sush123 last edited by Ahti

                @GrecKo @Christian-Ehrlicher @SGaist So Do I have to override setData function of QSqlTableModel in order for dataChanged to be implemented like this:

                bool UserModel::setData(const QModelIndex &index, const QVariant &value, int role){
                    if (index.isValid() && role == Qt::EditRole){
                        bool response = QSqlTableModel::setData(index, value, role);
                        response = QSqlTableModel::submitAll();
                        const QModelIndex idx = this->index(index.row(), 0);
                        emit dataChanged(idx, idx);    
                        return response;
                    }
                    return false;
                }
                

                That still doesn't update the view. Maybe because I didn't address the custom role but i don't know how to address it exactly please help.

                1 Reply Last reply Reply Quote 0
                • SGaist
                  SGaist Lifetime Qt Champion last edited by

                  See the dataChanged documentation.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  Ahti 1 Reply Last reply Reply Quote 0
                  • Ahti
                    Ahti @SGaist last edited by

                    @SGaist I already tried the documentation but I still don't understand please help

                    1 Reply Last reply Reply Quote 0
                    • SGaist
                      SGaist Lifetime Qt Champion last edited by

                      Did you saw the third argument of the signal ? The one you are currently not using in the code you provided. It's the one containing the custom roles.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      1 Reply Last reply Reply Quote 1
                      • First post
                        Last post