QTableview editing by row



  • Hello partners.

    I have experience with QStandardItemModel where the user is entering data in the cells using delegates and are updated directly in the model for later, with a "Save" button the data entered in the database is updated.

    What I want to do now is something different, when the user changes line (by means of Return, pressing outside the line that is being edited or because Tab is pressed in the last column of the row) a process of verification of the introduced data. If everything is fine, the database should be updated and if not, a message should be displayed with the errors.

    Looking for information I've seen things with QAbstractItemModel, the slots submit and revert but I do not completely understand it. For example, I do not understand how you are told to check data only when you switch lines.

    Could someone help me? A little example would be nice.

    Thank you very much.



  • Declare a private int currentRow= -1;
    then

    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)
    validateRow(currentRow);
    currentRow=newRow;
    });
    


  • That's not what I need. One thing is that the user can select the rows, in fact, I want it to be able to do it; and another is that when leaving the row editing mode using one of the three forms, make validation of the data in the row and if this has gone well, update the database. Any advice?



  • Subclass the delegate:

    #include <QStyledItemDelegate>
    class DataChangeDelegate : public QStyledItemDelegate{
        Q_OBJECT
        Q_DISABLE_COPY(DataChangeDelegate)
    public:
        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)
                dataChanged(index);
        }
        Q_SIGNAL void dataChanged(const QModelIndex &index);
    };
    

    then use:

    DataChangeDelegate* signalingDelegate=new DataChangeDelegate(this);
    connect(signalingDelegate,&DataChangeDelegate::dataChanged,this,[this](const QModelIndex& idx)->void{
    const int newRow= idx.isValid() ? idx.row():-1;
    if(newRow==currentRow) return;
    if(currentRow>=0)
    validateRow(currentRow);
    currentRow=newRow;
    });
    tableView->setItemDelegate(signalingDelegate);
    


  • I think that solution is not correct either. If the user is editing a row, it will not be validated until you change a data in another row, that is, if the user changes the value of column A of row 5 and click on row 7, with this solution row 5 would not be valid until a data item in row 7 was changed, which may or may not be the case. It is not a valid solution.

    Anyway thanks for the interest :-)



  • @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);
    

Log in to reply