Table Model Cell dependencies
-
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.- What would be a way to register relationships between cells?
- Does that exist within Qt's model/view infrastructure?
- 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(); }
-
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.- What would be a way to register relationships between cells?
- Does that exist within Qt's model/view infrastructure?
- 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(); }
@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 multiplesetData()
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.
-
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
. -
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
.@Viktor-Khristenko
Qt provides straightforward models. It does not provide the functionality of a spreadsheet like you describe. You havesetData()
,dataChanged()
signal or your own interface to those. You have to write your own code for whatever relationships or actions you have in mind.