Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QAbstractTableModel editing without clearing previous data in cell

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);
}
like image 352
DaveK Avatar asked Apr 25 '19 18:04

DaveK


People also ask

What is qabstracttablemodel used for?

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.

Should I use qabstractitemmodel or qabstractlistmodel for a tree view?

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.

How do I get the model index of a qabstracttablemodel?

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 ().

Is it possible to edit the contents of a qtableview?

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?


1 Answers

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.

like image 127
TrebledJ Avatar answered Sep 18 '22 05:09

TrebledJ