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. I don't understand QAbstractTableModel

I don't understand QAbstractTableModel

Scheduled Pinned Locked Moved Unsolved General and Desktop
6 Posts 3 Posters 715 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.
  • K Offline
    K Offline
    kaisbe
    wrote on last edited by
    #1

    While I have read the docs and tried to understand the Model-View architecture of QTableView UI component, I'm still unable to well bind data to table model.

    I used this class prototype for the implementation of QAbstractTableModel:

    class TableModel : public QAbstractTableModel
    {
    public:
        TableModel(QObject *parent = nullptr);
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
        int columnCount(const QModelIndex &parent = QModelIndex()) const override;
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
        QVariant headerData(int section, Qt::Orientation orientation,
                                        int role) const;
    

    the model has already an instance which is set for the table view. The data binding is implemented within the data() method:

    static std::vector<Task> tasks = {};
    
    QVariant TableModel::data(const QModelIndex &index, int role) const
    {
        int task_index = index.row();
        TaskProperty task_property = static_cast<TaskProperty>(index.column());
        Task task = tasks.at(static_cast<unsigned long>(task_index));
        QString cellValue = "";
        switch (task_property)
        {
        case NAME:
            cellValue = QString::fromStdString(task.name);
            break;
        default:
            break;
        }
        if (role == Qt::DisplayRole)
           return cellValue;
    
        return QVariant();
    }
    

    As described above, the data that has to be binded to the view, is within the vector tasks. But after this shared vector gets updated with newer values from an external class, nothing gets loaded within the view.

    I really got stuck at this point, and I'm unable to understand how data binding works for the model QAbstractTableModel and its view QTableView.

    Can anyone try to explain how this works please?

    sierdzioS 1 Reply Last reply
    0
    • K kaisbe

      While I have read the docs and tried to understand the Model-View architecture of QTableView UI component, I'm still unable to well bind data to table model.

      I used this class prototype for the implementation of QAbstractTableModel:

      class TableModel : public QAbstractTableModel
      {
      public:
          TableModel(QObject *parent = nullptr);
          int rowCount(const QModelIndex &parent = QModelIndex()) const override;
          int columnCount(const QModelIndex &parent = QModelIndex()) const override;
          QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
          QVariant headerData(int section, Qt::Orientation orientation,
                                          int role) const;
      

      the model has already an instance which is set for the table view. The data binding is implemented within the data() method:

      static std::vector<Task> tasks = {};
      
      QVariant TableModel::data(const QModelIndex &index, int role) const
      {
          int task_index = index.row();
          TaskProperty task_property = static_cast<TaskProperty>(index.column());
          Task task = tasks.at(static_cast<unsigned long>(task_index));
          QString cellValue = "";
          switch (task_property)
          {
          case NAME:
              cellValue = QString::fromStdString(task.name);
              break;
          default:
              break;
          }
          if (role == Qt::DisplayRole)
             return cellValue;
      
          return QVariant();
      }
      

      As described above, the data that has to be binded to the view, is within the vector tasks. But after this shared vector gets updated with newer values from an external class, nothing gets loaded within the view.

      I really got stuck at this point, and I'm unable to understand how data binding works for the model QAbstractTableModel and its view QTableView.

      Can anyone try to explain how this works please?

      sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by VRonin
      #2

      @kaisbe said in I don't understand QAbstractTableModel:

      As described above, the data that has to be binded to the view, is within the vector tasks. But after this shared vector gets updated with newer values from an external class, nothing gets loaded within the view.

      You need to emit dataChanged() from model if data has changed. If you added or removed some items, call beginInsertRows(), endInsertRows() etc. Without that the view does not know that anything has changed, so it won't update itself.

      (Z(:^

      1 Reply Last reply
      5
      • K Offline
        K Offline
        kaisbe
        wrote on last edited by
        #3

        @sierdzio said in I don't understand QAbstractTableModel:

        dataqChanged()

        Thanks for the quick response.

        OK, I understood, but could you provide me with a documentation link that talks about the need of emitting dataChanged() and calling beginInsertRows() + endInsertRows()?

        1 Reply Last reply
        0
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by VRonin
          #4

          https://doc.qt.io/qt-5/qabstractitemmodel.html#subclassing
          https://doc.qt.io/qt-5/model-view-programming.html#creating-new-models

          "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

          K 1 Reply Last reply
          3
          • VRoninV VRonin

            https://doc.qt.io/qt-5/qabstractitemmodel.html#subclassing
            https://doc.qt.io/qt-5/model-view-programming.html#creating-new-models

            K Offline
            K Offline
            kaisbe
            wrote on last edited by kaisbe
            #5

            @VRonin

            • Concerning the first link:

            The dataChanged() and headerDataChanged() signals must be emitted explicitly when reimplementing the setData() and setHeaderData() functions, respectively.

            If I understand correctly, I need to implement the setData() method, that is defined as:

            Sets the role data for the item at index to value.

            But, I don't understand what the role is - frankly I don't understand anything concerning setData() and how to emit dataChanged().

            • Concerning the second link:

            The model first calls the beginInsertRows() function to inform other components that the number of rows is about to change. The function specifies the row numbers of the first and last new rows to be inserted, and the model index for their parent item. After changing the string list, it calls endInsertRows() to complete the operation and inform other components that the dimensions of the model have changed, returning true to indicate success.

            Do I need to override the insertRows() method or just:

            1. call tablemodel->beginInsertRows()
            2. perform the push back of my static vector variable at this time
            3. call tablemodel->endInsertRows()
            1 Reply Last reply
            0
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by
              #6

              Depends which rout you are going down:

              • the model is the data
              • the model is an interface on top of the data

              My feeling is that you are in the second case i.e. you want a way to feed a view with data coming from somewhere else (static std::vector<Task> tasks)

              In this case whenever a Task in the vector is changed/inserted/removed from somewhere outside of the model you also have to communicate to the model that change happened. This is usually done via a signal connected to a slot in the model. This slot will then take care of finding out the QModelIndex that corresponds to the changed item and emit dataChanged.

              Chapter 3 of this book is excellent to explain how models work

              "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

              1 Reply Last reply
              3

              • Login

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