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. QAbstractTable subclass. Data doesn't update.
QtWS25 Last Chance

QAbstractTable subclass. Data doesn't update.

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 3 Posters 1.8k 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.
  • J Offline
    J Offline
    Jeff Barnes
    wrote on last edited by
    #1

    I'm having a bit of a time understanding the abstract table model. I implemented a subclass with the following code in the data() and setData() functions.

    QVariant SecureRoomModel::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid())
            return QVariant();
        SecureRoomControl *ctl = m_deviceInfoList[index.row()];
        int column = index.column();
        qDebug() << "data" << role;
        switch (role)
        {
        case Qt::DisplayRole:
            qDebug() << "Qt DisplayRole";
            switch (column)
            {
            case HEADER_IP:
                qDebug() << "IP DisplayRole" << ctl->secureRoomData()->ipAddress();
                return ctl->secureRoomData()->ipAddress();
            case HEADER_SERIAL:
                return genSerialImage(ctl);
            default:
                return QVariant();
            }
        default:
            return QVariant();
        }
    }
    
    bool SecureRoomModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
        qDebug() << "setData";
        int row = index.row();
        int column = index.column();
        if (row != m_deviceInfoList.size() - 1)
            return false;
        SecureRoomControl *ctl = m_deviceInfoList[row];
        switch(role)
        {
        case Qt::EditRole:
            if (column == HEADER_IP)
                ctl->ipAddressChanged(value.toString());
            else if (column == HEADER_SERIAL)
                ctl->serialNumberChanged(value.toString());
            emit dataChanged(index, index, QVector<int>() << Qt::DisplayRole);
            break;
        default:
            break;
        }
        return true;
    }
    
    
    

    When I edit data, it disappears from the table view. In other words, I double click in the HEADER_IP column cell of a row, type in information and press Enter, the backing data of my model was changed, but it disappears in the table view. It seems that all the rest of the data calls are called with the Qt::EditRole.

    Is this enough code to help? Any help appreciated.

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      if (row != m_deviceInfoList.size() - 1) << looks fishy
              return false;
      

      Shouldn't that be if (row >= m_deviceInfoList.size()) ?

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

      J 1 Reply Last reply
      1
      • SGaistS SGaist

        Hi,

        if (row != m_deviceInfoList.size() - 1) << looks fishy
                return false;
        

        Shouldn't that be if (row >= m_deviceInfoList.size()) ?

        J Offline
        J Offline
        Jeff Barnes
        wrote on last edited by
        #3

        @SGaist Thanks for the reply. The reason I have that check there is to only have the last row editable.

        My next attempt is to show some new qDebug messages.

        QVariant SecureRoomModel::data(const QModelIndex &index, int role) const
        {
            if (!index.isValid())
                return QVariant();
            SecureRoomControl *ctl = m_deviceInfoList[index.row()];
            int column = index.column();
            qDebug() << "data" << role;
            switch (role)
            {
            case Qt::DisplayRole:
                switch (column)
                {
                case HEADER_IP:
                    qDebug() << "IP DisplayRole" << ctl->secureRoomData()->ipAddress();
                    return ctl->secureRoomData()->ipAddress();
                case HEADER_SERIAL:
                    return genSerialImage(ctl);
                ...
                default:
                    return QVariant();
                }
            default:
                return QVariant();
            }
        }
        
        bool SecureRoomModel::setData(const QModelIndex &index, const QVariant &value, int role)
        {
            int row = index.row();
            qDebug() << "setData" << row << "of" << m_deviceInfoList.size() - 1;
            int column = index.column();
            if (row != m_deviceInfoList.size() - 1)
                return false;
            SecureRoomControl *ctl = m_deviceInfoList[row];
            switch(role)
            {
            case Qt::EditRole:
                if (column == HEADER_IP)
                    ctl->ipAddressChanged(value.toString());
                else if (column == HEADER_SERIAL)
                    ctl->serialNumberChanged(value.toString());
                emit dataChanged(index, index, QVector<int>() << Qt::DisplayRole);
                break;
            default:
                break;
            }
            return true;
        }
        void SecureRoomModel::onDataChanged(int row)
        {
            //update everything on that row
            QModelIndex top = createIndex(row, 0);
            QModelIndex bottom = createIndex(row, HEADER_STATUS);
            qDebug() << "onDataChanged row=" << row << "ip=" << m_deviceInfoList[row]->secureRoomData()->ipAddress();
            emit dataChanged(top, bottom, QVector<int>() << Qt::DisplayRole);
            emit saveRequired();
        }
        
        bool SecureRoomModel::addRow(RestaurantSettings *restaurantSettings)
        {
            int row = m_deviceInfoList.size();
            SecureRoomControl *ctl = new SecureRoomControl(restaurantSettings, row);
            QObject::connect(ctl, &SecureRoomControl::dataChanged, this, &SecureRoomModel::onDataChanged);
            QObject::connect(ctl, &SecureRoomControl::dataDeviceInfoComplete, this, &SecureRoomModel::onDataDeviceInfoComplete);
            QObject::connect(ctl, &SecureRoomControl::validIpAddress, this, &SecureRoomModel::onValidIpAddress);
            QObject::connect(ctl, &SecureRoomControl::validSerialNumber, this, &SecureRoomModel::onValidSerialNumber);
            QObject::connect(this, &SecureRoomModel::destroyed, ctl, &SecureRoomControl::deleteLater);
            QThread *thr = new QThread;
            QObject::connect(ctl, &SecureRoomControl::destroyed, thr, &QThread::quit);
            QObject::connect(thr, &QThread::finished, thr, &QThread::deleteLater);
            ctl->moveToThread(thr);
            thr->start();
            beginInsertRows(QModelIndex(), row, row);
            m_deviceInfoList.append(ctl);
            m_ipCellEnabled = true;
            m_serialCellEnabled = false;
            endInsertRows();
            emit dataChanged(this->createIndex(row, 0), this->createIndex(row, this->columnCount(QModelIndex())));
            return true;
        }
        
        

        The onDataChanged() function is a slot for handling signals by SecureRoomControl, which runs in a different thread, to notify the Model that data was changed by the controller and the model should update all of the columns. I wonder if it should be in the same thread.

        I fire up the table view, double click on the HEADER_IP column cell in the first row. I get the following output after double clicking.

        data 3
        data 10
        data 2
        data 6
        data 7
        data 9
        data 10
        data 1
        data 0
        IP DisplayRole ""
        data 8
        data 2
        

        Then I type in 192.168.14.50 and press the Enter key and see the following output.

        setData 0 of 0
        SecureRoomControl::ipAddressChanged "192.168.14.50"
        acquiringMac
        data 2
        onDataChanged row= 0 ip= "192.168.14.50"
        data 2
        data 2
        onDataChanged row= 0 ip= "192.168.14.50"
        setMac
        onDataChanged row= 0 ip= "192.168.14.50"
        onDataChanged row= 0 ip= "192.168.14.50"
        onDataChanged row= 0 ip= "192.168.14.50"
        

        The 2 value for the role debug is Qt::EditRole. No Qt::DisplayRole calls to data().

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Then you should also reimplement the flags method. It will be cleaner and make things clearer when reading your code.

          As for the dataChanged, I'd start with the default value, you can always optimise later on.

          If you have multiple threads accessing the model (that's completely valid), you should protect these access like for any resources accessed by multiple threads.

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

          VRoninV J 2 Replies Last reply
          2
          • SGaistS SGaist

            Then you should also reimplement the flags method. It will be cleaner and make things clearer when reading your code.

            As for the dataChanged, I'd start with the default value, you can always optimise later on.

            If you have multiple threads accessing the model (that's completely valid), you should protect these access like for any resources accessed by multiple threads.

            VRoninV Offline
            VRoninV Offline
            VRonin
            wrote on last edited by
            #5

            Try passing your model through the Model Test it's much easier to detect what you are doing wrong that way

            @SGaist said in QAbstractTable subclass. Data doesn't update.:

            Then you should also reimplement the flags method

            That is the correct way to restrict what indexes can be edited and not.

            If you have multiple threads accessing the model (that's completely valid)

            It's valid if the model itself lives in the GUI thread. The views calls methods on the model directly so unless you lock everything down you'll have a race condition.

            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
            ~Napoleon Bonaparte

            On a crusade to banish setIndexWidget() from the holy land of Qt

            J 1 Reply Last reply
            1
            • SGaistS SGaist

              Then you should also reimplement the flags method. It will be cleaner and make things clearer when reading your code.

              As for the dataChanged, I'd start with the default value, you can always optimise later on.

              If you have multiple threads accessing the model (that's completely valid), you should protect these access like for any resources accessed by multiple threads.

              J Offline
              J Offline
              Jeff Barnes
              wrote on last edited by
              #6

              @SGaist Thanks for your help. Great suggestions! I decided to start over with a new model and add the features step by step according to the tutorials/examples. Got it working. Marking the issue as solved.

              For anyone who reads this, if you are having trouble with the model, start with the simple read/write examples, getting them to work. If you have specialized controller needs, add them in step by step, checking as you go.

              1 Reply Last reply
              0
              • VRoninV VRonin

                Try passing your model through the Model Test it's much easier to detect what you are doing wrong that way

                @SGaist said in QAbstractTable subclass. Data doesn't update.:

                Then you should also reimplement the flags method

                That is the correct way to restrict what indexes can be edited and not.

                If you have multiple threads accessing the model (that's completely valid)

                It's valid if the model itself lives in the GUI thread. The views calls methods on the model directly so unless you lock everything down you'll have a race condition.

                J Offline
                J Offline
                Jeff Barnes
                wrote on last edited by
                #7

                @VRonin Thanks for the ModelTest tip. I will definitely use this today.

                1 Reply Last reply
                0

                • Login

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