I have created a model based off of QAbstractTableModel that allows the user to edit data in that model. The model is displayed in a QTableView in a QMainWindow. So far in my model I am able to make the cells editable, and save whatever the user types in after editing is finished.
The issue is that when the user begins editing, it 'clears' the previous contents of that cell. So if for example I only wanted to change the spelling of a string in a cell, I have to re-type the entire value. I would like when editing that the editor would start with the data that is already in the model, rather than empty.
How can I do that?
Example of the issue:
Before I begin editing a cell:
As soon as I begin editing, the cell is empty. I would like it to star with the previous value already in the model:
Here is a minimal example of my model. My actual model is much larger and uses a struct instead of just a 2D array of QVariants to store the data.
Header:
const int COLS= 2;
const int ROWS= 6;
class EditableTableModel : public QAbstractTableModel
{
Q_OBJECT
private:
QVariant tableData[ROWS][COLS];
public:
EditableTableModel(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;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
signals:
void editCompleted(QString);
};
Implementation:
EditableTableModel::EditableTableModel(QObject *parent)
: QAbstractTableModel(parent)
{
}
int EditableTableModel::rowCount(const QModelIndex & /*parent*/) const
{
return ROWS;
}
int EditableTableModel::columnCount(const QModelIndex & /*parent*/) const
{
return COLS;
}
QVariant EditableTableModel::data(const QModelIndex &index, int role) const
{
int row = index.row();
int col = index.column();
switch (role) {
case Qt::DisplayRole:
return tableData[row][col];
}
return QVariant();
}
bool EditableTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role == Qt::EditRole) {
if (!checkIndex(index))
return false;
tableData[index.row()][index.column()] = value;
return true;
}
return false;
}
QVariant EditableTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
switch (section) {
case 0:
return QString("First Name");
case 1:
return QString("Last Name");
}
}
return QVariant();
}
Qt::ItemFlags EditableTableModel::flags(const QModelIndex &index) const
{
return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
}
More... QAbstractTableModel provides a standard interface for models that represent their data as a two-dimensional array of items. It is not used directly, but must be subclassed.
Since the model provides a more specialized interface than QAbstractItemModel, it is not suitable for use with tree views, although it can be used to provide data to a QListView. If you need to represent a simple list of items, and only need a model to contain a single column of data, subclassing the QAbstractListModel may be more appropriate.
To retrieve a model index corresponding to an item in the model, use index () and provide only the row and column numbers. When subclassing QAbstractTableModel, you must implement rowCount (), columnCount (), and data ().
It allows us view and edit every custom table model we can imagine. However, the default way of editing is rather clunky, especially when compared with “industry standard” applications like Microsoft Excel or Google Sheets. Wouldn’t it be nice to edit the QTableView contents like in one of these applications?
Data should be returned for Qt::EditRole
in the data()
method. The following should work:
QVariant EditableTableModel::data(const QModelIndex &index, int role) const
{
int row = index.row();
int col = index.column();
switch (role) {
case Qt::DisplayRole:
case Qt::EditRole: // <-- add this line
return tableData[row][col];
}
return QVariant();
}
Note that the above switch-case uses something known as fallthrough, so that the switch-case will match for both Qt::DisplayRole
and Qt::EditRole
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With