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. Inconsistency between model and view while updating QSqlTableModel cell
QtWS25 Last Chance

Inconsistency between model and view while updating QSqlTableModel cell

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
qmlmodel-viewmodelviewmodel view prog
9 Posts 4 Posters 1.3k Views
  • 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.
  • A Offline
    A Offline
    Ahti
    wrote on 21 Feb 2020, 05:16 last edited by Ahti
    #1

    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
    0
    • G Offline
      G Offline
      GrecKo
      Qt Champions 2018
      wrote on 21 Feb 2020, 08:13 last edited by
      #2

      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.

      A 2 Replies Last reply 27 Feb 2020, 17:02
      3
      • G GrecKo
        21 Feb 2020, 08:13

        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.

        A Offline
        A Offline
        Ahti
        wrote on 27 Feb 2020, 17:02 last edited by
        #3
        This post is deleted!
        1 Reply Last reply
        0
        • G GrecKo
          21 Feb 2020, 08:13

          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.

          A Offline
          A Offline
          Ahti
          wrote on 28 Feb 2020, 03:30 last edited by
          #4
          This post is deleted!
          1 Reply Last reply
          0
          • S Offline
            S Offline
            sush123
            wrote on 28 Feb 2020, 05:30 last edited by
            #5

            Hi Ahti,

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

            A 1 Reply Last reply 28 Feb 2020, 05:38
            2
            • S sush123
              28 Feb 2020, 05:30

              Hi Ahti,

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

              A Offline
              A Offline
              Ahti
              wrote on 28 Feb 2020, 05:38 last edited by Ahti
              #6

              @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
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on 28 Feb 2020, 20:35 last edited by
                #7

                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

                A 1 Reply Last reply 29 Feb 2020, 15:17
                0
                • SGaistS SGaist
                  28 Feb 2020, 20:35

                  See the dataChanged documentation.

                  A Offline
                  A Offline
                  Ahti
                  wrote on 29 Feb 2020, 15:17 last edited by
                  #8

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

                  1 Reply Last reply
                  0
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on 29 Feb 2020, 20:04 last edited by
                    #9

                    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
                    1

                    1/9

                    21 Feb 2020, 05:16

                    • Login

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