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. Table Model Cell dependencies

Table Model Cell dependencies

Scheduled Pinned Locked Moved Unsolved General and Desktop
4 Posts 2 Posters 164 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.
  • V Offline
    V Offline
    Viktor Khristenko
    wrote on last edited by
    #1

    Hello,

    I would like to create an excel like table view/model example. Below is a simple editable table example.
    What i need to add is the ability to update a cell if some other cell changed, in particular if this is not a one-off thing but can trigger various updates recursively.

    using just setData and updating more than 1 index is not a good idea as that does not scale.

    1. What would be a way to register relationships between cells?
    2. Does that exist within Qt's model/view infrastructure?
    3. Can we intercept dataChanged signal?

    Thanks a lot!

    VK

    #include <qnamespace.h>
    #include <iostream>
    
    #include "fmt/core.h"
    
    #include "QApplication"
    #include "QString"
    #include "QTableView"
    #include "QMainWindow"
    #include "QAbstractTableModel"
    #include "QTableView"
    #include "QHeaderView"
    
    class SimpleTableModel : public QAbstractTableModel {
    public:
        SimpleTableModel(
                std::vector<QString> const&,
                std::vector<std::vector<QVariant>> const&,
                QObject* parent = nullptr);
    
        int rowCount(QModelIndex const& parent = QModelIndex()) const override;
        int columnCount(QModelIndex const& parent = QModelIndex()) const override;
    
        QVariant data(QModelIndex const&, int role) const override;
        Qt::ItemFlags flags(QModelIndex const&) const override;
        bool setData(QModelIndex const& index, QVariant const& value, int role) override;
    
        QVariant headerData(
                int section, Qt::Orientation orientation,
                int role = Qt::DisplayRole) const override;
    private:
        std::vector<QString> column_names_;
        std::vector<std::vector<QVariant>> data_;
    };
    
    SimpleTableModel::SimpleTableModel(
            std::vector<QString> const& column_names,
            std::vector<std::vector<QVariant>> const& data,
            QObject* parent)
        : QAbstractTableModel{parent}
        , column_names_{column_names}
        , data_{data}
    {}
    
    Qt::ItemFlags SimpleTableModel::flags(QModelIndex const& index) const {
        if (index.isValid()) {
            return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
        }
    
        return QAbstractTableModel::flags(index);
    }
    
    int SimpleTableModel::rowCount(QModelIndex const& parent) const {
        return static_cast<int>(data_.size());
    }
    
    int SimpleTableModel::columnCount(QModelIndex const& parent) const {
        return data_.size() == 0
            ? 0
            : static_cast<int>(data_[0].size());
    }
    
    bool SimpleTableModel::setData(
            QModelIndex const& index, QVariant const& value, int role) {
        if (!index.isValid()) {
            return false;
        }
    
        if (index.row() >= rowCount()) {
            return false;
        }
    
        if (role != Qt::EditRole) {
            return false;
        }
    
        auto& row = data_[index.row()];
        if (index.column() >= columnCount()) {
            return false;
        }
        row[index.column()] = value;
        emit dataChanged(index, index);
        return true;
    }
    
    QVariant SimpleTableModel::data(QModelIndex const& index, int role) const {
        if (!index.isValid()) 
            return {};
    
        if (index.row() >= rowCount()) 
            return {};
    
        if (role != Qt::DisplayRole)
            return {};
    
        auto const& row = data_[index.row()];
        if (index.column() >= columnCount()) 
            return {};
    
        return row[index.column()];
    }
    
    QVariant SimpleTableModel::headerData(
            int section, 
            Qt::Orientation orientation,
            int role) const {
        if (role != Qt::DisplayRole)
            return {};
    
        if (orientation == Qt::Horizontal) {
            if (section<0 || section >= columnCount()) {
                return {};
            }
    
            return column_names_[section];
        } else {
            if (section<0 || section >= rowCount()) {
                return {};
            }
    
            return QStringLiteral("Row %1").arg(section);
        }
    
        return {};
    }
    
    int main(int argc, char** argv) {
        ::fmt::print("hello world!\n");
    
        QApplication app{argc, argv};
        QMainWindow w{nullptr};
        w.resize(640, 480);
    
        auto view = QTableView{&w};
        std::vector<QString> column_names = {
            QString{"Red"}, QString{"Green"}, QString{"Blue"}
        };
        std::vector<std::vector<QVariant>> data = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };
        auto model = SimpleTableModel{column_names, data};
        view.setModel(&model);
        view.horizontalHeader()->setVisible(true);
        view.resize(480, 360);
    
        w.show();
        return app.exec();
    }
    
    
    JonBJ 1 Reply Last reply
    0
    • V Viktor Khristenko

      Hello,

      I would like to create an excel like table view/model example. Below is a simple editable table example.
      What i need to add is the ability to update a cell if some other cell changed, in particular if this is not a one-off thing but can trigger various updates recursively.

      using just setData and updating more than 1 index is not a good idea as that does not scale.

      1. What would be a way to register relationships between cells?
      2. Does that exist within Qt's model/view infrastructure?
      3. Can we intercept dataChanged signal?

      Thanks a lot!

      VK

      #include <qnamespace.h>
      #include <iostream>
      
      #include "fmt/core.h"
      
      #include "QApplication"
      #include "QString"
      #include "QTableView"
      #include "QMainWindow"
      #include "QAbstractTableModel"
      #include "QTableView"
      #include "QHeaderView"
      
      class SimpleTableModel : public QAbstractTableModel {
      public:
          SimpleTableModel(
                  std::vector<QString> const&,
                  std::vector<std::vector<QVariant>> const&,
                  QObject* parent = nullptr);
      
          int rowCount(QModelIndex const& parent = QModelIndex()) const override;
          int columnCount(QModelIndex const& parent = QModelIndex()) const override;
      
          QVariant data(QModelIndex const&, int role) const override;
          Qt::ItemFlags flags(QModelIndex const&) const override;
          bool setData(QModelIndex const& index, QVariant const& value, int role) override;
      
          QVariant headerData(
                  int section, Qt::Orientation orientation,
                  int role = Qt::DisplayRole) const override;
      private:
          std::vector<QString> column_names_;
          std::vector<std::vector<QVariant>> data_;
      };
      
      SimpleTableModel::SimpleTableModel(
              std::vector<QString> const& column_names,
              std::vector<std::vector<QVariant>> const& data,
              QObject* parent)
          : QAbstractTableModel{parent}
          , column_names_{column_names}
          , data_{data}
      {}
      
      Qt::ItemFlags SimpleTableModel::flags(QModelIndex const& index) const {
          if (index.isValid()) {
              return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
          }
      
          return QAbstractTableModel::flags(index);
      }
      
      int SimpleTableModel::rowCount(QModelIndex const& parent) const {
          return static_cast<int>(data_.size());
      }
      
      int SimpleTableModel::columnCount(QModelIndex const& parent) const {
          return data_.size() == 0
              ? 0
              : static_cast<int>(data_[0].size());
      }
      
      bool SimpleTableModel::setData(
              QModelIndex const& index, QVariant const& value, int role) {
          if (!index.isValid()) {
              return false;
          }
      
          if (index.row() >= rowCount()) {
              return false;
          }
      
          if (role != Qt::EditRole) {
              return false;
          }
      
          auto& row = data_[index.row()];
          if (index.column() >= columnCount()) {
              return false;
          }
          row[index.column()] = value;
          emit dataChanged(index, index);
          return true;
      }
      
      QVariant SimpleTableModel::data(QModelIndex const& index, int role) const {
          if (!index.isValid()) 
              return {};
      
          if (index.row() >= rowCount()) 
              return {};
      
          if (role != Qt::DisplayRole)
              return {};
      
          auto const& row = data_[index.row()];
          if (index.column() >= columnCount()) 
              return {};
      
          return row[index.column()];
      }
      
      QVariant SimpleTableModel::headerData(
              int section, 
              Qt::Orientation orientation,
              int role) const {
          if (role != Qt::DisplayRole)
              return {};
      
          if (orientation == Qt::Horizontal) {
              if (section<0 || section >= columnCount()) {
                  return {};
              }
      
              return column_names_[section];
          } else {
              if (section<0 || section >= rowCount()) {
                  return {};
              }
      
              return QStringLiteral("Row %1").arg(section);
          }
      
          return {};
      }
      
      int main(int argc, char** argv) {
          ::fmt::print("hello world!\n");
      
          QApplication app{argc, argv};
          QMainWindow w{nullptr};
          w.resize(640, 480);
      
          auto view = QTableView{&w};
          std::vector<QString> column_names = {
              QString{"Red"}, QString{"Green"}, QString{"Blue"}
          };
          std::vector<std::vector<QVariant>> data = {
              {1, 2, 3},
              {4, 5, 6},
              {7, 8, 9}
          };
          auto model = SimpleTableModel{column_names, data};
          view.setModel(&model);
          view.horizontalHeader()->setVisible(true);
          view.resize(480, 360);
      
          w.show();
          return app.exec();
      }
      
      
      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @Viktor-Khristenko said in Table Model Cell dependencies:

      using just setData and updating more than 1 index is not a good idea as that does not scale.

      I don't understand this. setData() is (ultimately) the only way to update the value stored at an index in a model, so if you need to update multiple index values you will need multiple setData() calls.

      Yes, you can "intercept dataChanged signal" by attaching a slot to it. Because it is a signal I don't think you can subclass and override it.

      1 Reply Last reply
      0
      • V Offline
        V Offline
        Viktor Khristenko
        wrote on last edited by
        #3

        Thanks a lot for getting back so quickly!

        What i meant by using just setData and updating more than 1 index is not a good idea as that does not scale. is that if one has certain relationships between cells,
        e.g. like a formula in excel, then when one updates a cell's value (in ui), there should be a way, an api, to preprogram some such relationships that an update is intercepted and in turn triggers an update of another cell and that, in turn, triggers an update of another cell.

        I think the answer to my question is that Qt does not have a predefined api for such relationships. But one can easily build that of course, that is clear. And yes ultimately i would be calling setData.

        JonBJ 1 Reply Last reply
        0
        • V Viktor Khristenko

          Thanks a lot for getting back so quickly!

          What i meant by using just setData and updating more than 1 index is not a good idea as that does not scale. is that if one has certain relationships between cells,
          e.g. like a formula in excel, then when one updates a cell's value (in ui), there should be a way, an api, to preprogram some such relationships that an update is intercepted and in turn triggers an update of another cell and that, in turn, triggers an update of another cell.

          I think the answer to my question is that Qt does not have a predefined api for such relationships. But one can easily build that of course, that is clear. And yes ultimately i would be calling setData.

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @Viktor-Khristenko
          Qt provides straightforward models. It does not provide the functionality of a spreadsheet like you describe. You have setData(), dataChanged() signal or your own interface to those. You have to write your own code for whatever relationships or actions you have in mind.

          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