4

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?

Zero
  • 11,593
  • 9
  • 52
  • 70
  • I am not sure, but maybe it's wrong EditTriggers set in your view? QAbstractItemView::CurrentChanged looks like it could cause this behaviour. – Greenflow Aug 26 '13 at 09:14
  • Is it ok to use blocksignals from the model, while editing ? and unblock signal once you done editing ?. – Ashif Aug 26 '13 at 11:05

4 Answers4

3

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

Leonid
  • 74
  • 4
1

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 :)

Moritz H.
  • 21
  • 5
0

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;
}
Mostafa
  • 670
  • 1
  • 10
  • 20
  • 1
    I've done this - it's not the problem. The problem is that while the user is editing the UI and before `setData` is called the UI refreshes due to a `dataChanged` event and wipes the partially input data. – Zero Sep 05 '13 at 03:27
  • are you using QAbstractItemDelegate? – Mostafa Sep 05 '13 at 07:00
  • No, I'm not using `AbstractItemDelegate` – Zero Sep 06 '13 at 01:55
  • No - I don't think that'd be useful (unless I made a SSCE) as the code is too complex. The reason I think it's not worth my time is I now believe it's Qt behaviour that if the dataChanged event is raised for a cell that is being edited the edit value is reset to the new data value. I believe this can be worked around by implementing a QItemDelegate which can handle the events any way I want rather than relying on Qt default delegate behaviour behaviour. I'll update this QA with my progress. – Zero Sep 09 '13 at 05:25
0

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 });
JeFf
  • 346
  • 5
  • 16