How create a calculated column on a QSqlTableModel?



  • I would like to show a calculated column on a QTableView where the source is a QSqlTableModel. I've tried a custom QIdentityProxyModel, but the data method for the added column is never called.

    For example, if the database has 3 fields, and added a column with the addColumn method, the data method is never called with an index with column 3, only 0, 1 and 2 (the 3 database fields). However, columnCount returns 4 (3 database fields + 1 of the added column).

    class CalculatedColumn
    {
    public:
        CalculatedColumn();
        virtual QVariant calculate(int row) const = 0;
    };
    
    
    class SqlQueryModelCalculatedColumns: public QIdentityProxyModel
    {
    public:
        SqlQueryModelCalculatedColumns(QObject *parent = 0);
        void addColumn(CalculatedColumn *column);
        int columnCount(const QModelIndex &parent) const override;
        QVariant data(const QModelIndex &index, int role) const override;    
    private:
        QVector<CalculatedColumn *> m_columns;
    }
    
    
    SqlQueryModelCalculatedColumns::SqlQueryModelCalculatedColumns(QObject *parent): QIdentityProxyModel(parent)
    {
    }
    
    void SqlQueryModelCalculatedColumns::addColumn(CalculatedColumn *column)
    {
        const int count = sourceModel()->columnCount();
        beginInsertColumns(QModelIndex(), count, count);
        m_columns.append(column);
        endInsertColumns();
    }
    
    int SqlQueryModelCalculatedColumns::columnCount(const QModelIndex &parent) const
    {
        return sourceModel()->columnCount(parent) + m_columns.count();
    }
    
    QVariant SqlQueryModelCalculatedColumns::data(const QModelIndex &index, int role) const
    {
        const int column = index.column();
        const int count = sourceModel()->columnCount();
        if (column < count) {
            return sourceModel()->data(index, role);
        }
        else {
            const int iCalculatedColumn = column - count;
            CalculatedColumn *calculatedColumn = m_columns.at(iCalculatedColumn);
            return calculatedColumn->calculate(index.row());
        }
    }
    
    

  • Lifetime Qt Champion

    Hi,

    Why not subclass QSqlTableModel, reimplement columnCount and do your magic in data ?



  • I did it. It was the first attempt, but occurs the same.



  • @lqsa
    If you're saying you did originally take @SGaist 's approach, but it "didn't work", we'll need to see that code....



  • Only appears the dataset columns:

    class SqlTableModel : public QSqlTableModel {
    public:
        explicit SqlTableModel(QObject *parent = 0);    
        QVariant data(const QModelIndex &index, int role) const override;
        int columnCount(const QModelIndex &parent) const override;
    };
    
    
    
    SqlTableModel::SqlTableModel(QObject *parent): QSqlTableModel(parent)
    {
    }
    
    QVariant SqlTableModel::data(const QModelIndex &index, int role) const
    {
        if ((role == Qt::DisplayRole) && (index.column() == columnCount(QModelIndex()))) {
            return "Hello";
        }
        else {
            return QSqlTableModel::data(index, role);
        }
    }
    
    int SqlTableModel::columnCount(const QModelIndex &parent) const
    {
        const int count = QSqlTableModel::columnCount(parent) +1;
        return count;
    }
    

    0_1530094290605_Table.png



  • @lqsa said in How create a calculated column on a QSqlTableModel?:

    index.column() == columnCount(QModelIndex())

    How is this right? Index column will never be equal to columnCount()? Don't you mean
    index.column() == columnCount(QModelIndex()) - 1
    ?

    I don't know whether that will solve your problem, but it's a start.



  • @JonB Yes, must be -1. Now this simple sample works. Thank you very much.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.