Validating user input in a QTableView
Asked Answered
O

2

11

I have a QTableView and I want to validate user input. If user insert an invalid value in a cell of the QTableView, I want to highlight that cell and disable a QPushButton.

How can I achieve this? Can I use QValidator?

Oletta answered 28/10, 2014 at 17:27 Comment(0)
C
14

Yes, you can do this, use custom QItemDelegate for this purpose (I used QIntValidator just as example).

Header:

#ifndef ITEMDELEGATE_H
#define ITEMDELEGATE_H

#include <QItemDelegate>

class ItemDelegate : public QItemDelegate
{
    Q_OBJECT
public:
    explicit ItemDelegate(QObject *parent = 0);

protected:
    QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    void setEditorData(QWidget * editor, const QModelIndex & index) const;
    void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const;
    void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const;

signals:

public slots:

};

#endif // ITEMDELEGATE_H

Cpp

#include "itemdelegate.h"
#include <QLineEdit>
#include <QIntValidator>

ItemDelegate::ItemDelegate(QObject *parent) :
    QItemDelegate(parent)
{
}

QWidget *ItemDelegate::createEditor(QWidget *parent,
                                    const QStyleOptionViewItem &option,
                                    const QModelIndex &index) const
{
    QLineEdit *editor = new QLineEdit(parent);
    editor->setValidator(new QIntValidator);
    return editor;
}


void ItemDelegate::setEditorData(QWidget *editor,
                                 const QModelIndex &index) const
{
    QString value =index.model()->data(index, Qt::EditRole).toString();
        QLineEdit *line = static_cast<QLineEdit*>(editor);
        line->setText(value);
}


void ItemDelegate::setModelData(QWidget *editor,
                                QAbstractItemModel *model,
                                const QModelIndex &index) const
{
    QLineEdit *line = static_cast<QLineEdit*>(editor);
    QString value = line->text();
    model->setData(index, value);
}


void ItemDelegate::updateEditorGeometry(QWidget *editor,
                                        const QStyleOptionViewItem &option,
                                        const QModelIndex &index) const
{
    editor->setGeometry(option.rect);
}

Usage:

#include "itemdelegate.h"
//...
ItemDelegate *itDelegate = new  ItemDelegate;
ui->tableView->setItemDelegate(itDelegate);

In this case user will not be able input wrong data, but you can use next:

void ItemDelegate::setModelData(QWidget *editor,
                                QAbstractItemModel *model,
                                const QModelIndex &index) const
{
    QLineEdit *line = static_cast<QLineEdit*>(editor);

    QIntValidator validator;
    int pos = 0;
    QString data = line->text();
    if(validator.validate(data,pos) != QValidator::Acceptable)
    {
        qDebug() << "not valid";//do something
    }
    else
    {
        model->setData(index, data);
    }
}

But in this case don't forget remove editor->setValidator(new QIntValidator); line from your code

Conveyancer answered 28/10, 2014 at 17:41 Comment(2)
Thank you, it works. But I can't delete the numbers in the cells when i insert a valid input. What should I do?Oletta
@Aimcorz I suppose that you use my first example, so on my computer validator blocks enter but changing selection to another cell works normal. I can suggest you use my second example, provide some way to avoid this, for example set empty string model->setData(index,"",Qt::EditRole); or something else.Conveyancer
W
5

I worked through the PyQt/PySide implementation of Kosovan's answer. I am including the python code here for those who are not working in C++:

from PySide2 import QtWidgets, QtCore, QtGui


class ItemDelegate(QtWidgets.QItemDelegate):
    def __init__(self, parent):
        super().__init__(parent)
    
    def createEditor(self, parent, option, index):
        editor = QtWidgets.QLineEdit(parent)
        editor.setValidator(QtGui.QIntValidator())
        return editor

    def setEditorData(self, editor, index):
        value = str(index.model()._data[index.row()][index.column()])
        editor.setText(value)
    
    def setModelData(self, editor, model, index):
        model.setData(index, editor.text(), QtCore.Qt.EditRole)
    
    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)


class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self._data = data
        
    def data(self, index, role):
        if role == QtCore.Qt.DisplayRole:
            return str(self._data[index.row()][index.column()])
    
    def rowCount(self, index):
        return len(self._data)
        
    def columnCount(self, index):
        return len(self._data[0])
    
    def setData(self, index, value, role):
        if role == QtCore.Qt.EditRole:
            try:
                value = int(value)
            except ValueError:
                return False
            self._data[index.row()][index.column()] = value
            return True
        return False

    def flags(self, index):
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        
        data = [
            [1, 2], 
            [3, 4], 
            [5, 6],
        ]
        
        self.model = TableModel(data)
        
        self.table = QtWidgets.QTableView()
        self.table.setModel(self.model)
        self.table.setItemDelegate(ItemDelegate(self))
        
        self.setCentralWidget(self.table)


if __name__ == '__main__':
    app = QtWidgets.QApplication()
    win = MainWindow()
    win.show()
    app.exec_()
Weatherly answered 18/8, 2021 at 1:22 Comment(3)
You're the real MVP. Thanks!Tabina
I appreciate knowing that it was helpful to someone else.Weatherly
You rock! thx so much for this, I was starting to get a headache trying to work out how to translate this to Python when I noticed your answer :'D.Halda

© 2022 - 2024 — McMap. All rights reserved.