Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validating user input in a QTableView

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?

like image 463
splunk Avatar asked Oct 28 '14 17:10

splunk


People also ask

How is input validated?

Input validation is the process of testing input received by the application for compliance against a standard defined within the application. It can be as simple as strictly typing a parameter and as complex as using regular expressions or business logic to validate input.

What is validate user input?

Input validation (also known as data validation) is the proper testing of any input supplied by a user or application. Input validation prevents improperly formed data from entering an information system.

Why do we need to validate the user input?

Input validation strategies It is always recommended to prevent attacks as early as possible in the processing of the user's (attacker's) request. Input validation can be used to detect unauthorized input before it is processed by the application.


2 Answers

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

like image 166
Kosovan Avatar answered Sep 30 '22 07:09

Kosovan


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_()
like image 32
chart328 Avatar answered Sep 30 '22 05:09

chart328