@blastdoman You are correct, let's try this: #include <QStyledItemDelegate> class DataChangeDelegate : public QStyledItemDelegate{ Q_OBJECT Q_DISABLE_COPY(DataChangeDelegate) public: enum{IsDirtyRole=Qt::UserRole + 44}; explicit DataChangeDelegate(QObject* parent=Q_NULLPTR) :QStyledItemDelegate(parent) {} virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE{ const QVariant oldData = index.data(Qt::EditRole); QStyledItemDelegate::setModelData(editor,model,index); if(index.data(Qt::EditRole)!=oldData) model->setData(index,true,IsDirtyRole); } }; DataChangeDelegate* signalingDelegate=new DataChangeDelegate(this); connect(tableView->selectionModel(),&QItemSelectionModel::currentChanged,this,[this](const QModelIndex& idx)->void{ const int newRow= idx.isValid() ? idx.row():-1; if(newRow==currentRow) return; if(currentRow>=0){ const int maxCols =idx.model()->columnCount(idx.parent()); for(int i=0;i<maxCols ;++i){ if(idx.model()->index(currentRow,i,idx.parent()).data(DataChangeDelegate::IsDirtyRole).toBool()){ validateRow(currentRow); /* inside validateRow call something like: for(int i=0;i<model->columnCount();++i) model->setData(model->index(currentRow,i),QVariant(),DataChangeDelegate::IsDirtyRole); */ break; } } } currentRow=newRow; }); tableView->setItemDelegate(signalingDelegate);