QAbstractTableModel editing without clearing previous data in cell
Asked Answered
C

1

6

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:

Before editing

As soon as I begin editing, the cell is empty. I would like it to star with the previous value already in the model:

Once editing begins

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);
}
Certify answered 25/4, 2019 at 18:7 Comment(0)
F
7

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.

Forgetful answered 25/4, 2019 at 18:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.