QTableView: dataChanged event clears cell being ed

2019-07-07 07:48发布

问题:

Working with a QTableView and QAbstractTableModel - when the model emits a dataChanged event for the cell being edited, the string the user has typed in the cell (but not pressed enter to 'commit' the edit) is erased.

Example: Click a cell, type '123', cell is still in edit mode waiting for more text, dataChanged is emitted and the '123' is erased, leaving an empty cell in edit mode.

Does anyone know how to stop this behaviour, or how the model can detect when the cell is being edited to prevent dataChanged events being raised for that cell?

回答1:

I had the same problem. The thing is, that data() function is called with different role parameter. For displaying role==Qt::DisplayRoleand while editing it is called with role==Qt::EditRole. For example try changing

QVariant MyModel::data(const QModelIndex & index, int role) const
{
  if (role == Qt::DisplayRole)
    return QString("Text to Edit");
}

to

QVariant MyModel::data(const QModelIndex & index, int role) const
{
  if (role == Qt::DisplayRole || role == Qt::EditRole)
    return QString("Text to Edit");
}

that should do the trick



回答2:

I had the same problem and found an approach without writing my own Delegate:

The problem is exactly how you described it: The data gets updated in the Background and everything you Edit gets cleared out because the dataChanged Event updates all values thus calling the data function, which returns an empty QVariant() Object if nothing is specified for the Qt::EditRole. Even Leonid's answer would always overwrite your edits with the same QString("Text to Edit").

So what I did was this:

Introduce a member variable and dafine it mutable so it can be changed by the const data function:

mutable bool m_updateData = true;

In your background data updating function, check for m_update date before emmitting the dataChanged Signal:

if (m_updateData)
    emit(dataChanged(index, index));

In your data function, check for the edit role and set m_updateData to false:

if (role == Qt::EditRole)
{
    m_updateData = false;
}

After the Edit is finished, the setData function is called, where you update the data in your model. Reset m_updateDate to true after you have done that.

This works perfectly for me :)



回答3:

Check your model class, you should override the setData method in your model. If every thing is correct it will update model after editing data... please let me know if you have another implementation

bool MyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.isValid() && role == Qt::EditRole) {
        int row = index.row();
        int col = index.column();

            //// change data

        emit(dataChanged(index, index));
        return true;
    }

    return false;
}


回答4:

I think that you should use dataChanged event only for indexes that are not being edited or only for Qt::ItemDataRole::DisplayRole. E.g. to update only second column for every row use:

emit dataChanged(index(0, 1),
 index(rowCount() - 1, 1),
 QVector<int>{ Qt::ItemDataRole::DisplayRole });


标签: qt qtableview