Important: Please read the Qt Code of Conduct -

Add read-only diff column to QSortFilterProxyModel that calculates on model data

  • Wow, thanks for all of the effort, octal! I'm still sketchy on subclassing Qt classes as far as what works and what to pass forward.

    I tried the above, but didn't see any difference in the Diff column (its still blank.) I tried commenting out the insertColumns line, but that only removed the column from the view.

    Also, the Diff column has no header displayed, which is weird since I entered your headerData function above.

    Another weird thing is that I am counting the number of fields and when I include the insertColumns and your code for the subclass, it actually shows 8 columns numbered (0 - 7.)

    Is this a common task to ask of the Qt (adding a meta-field that isn't really in the source table?)

    Thanks again.

  • Damn, I forgot one important thing : the index.

    Because of that, I think it would actually be better to directly subclass QSqlTableModel. I'm a little bit tired, so I'll let you with this code sample :

    class MyCustomModel : public QSqlTableModel {

    static const int DifferenceColumn = 2;


    MyCustomModel(QObject *parent = 0)
    : QSqlTableModel(parent) {

    int columnCount(const QModelIndex &parent) const
    const int count = QSqlTableModel::columnCount(parent);
    return count + 1;

    Qt::ItemFlags flags(const QModelIndex &index) const
    if (index.column() == DifferenceColumn)
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
    return QSqlTableModel::flags(index);

    QVariant data(const QModelIndex &index, int role) const
    if (index.column() == DifferenceColumn && role == Qt::DisplayRole)
    const int firstColumnIndex = fieldIndex("data1");
    const int secondColumnIndex = fieldIndex("data2");
    const QModelIndex dataIndex1 = this->index(index.row(), firstColumnIndex);
    const QModelIndex dataIndex2 = this->index(index.row(), secondColumnIndex);

           const QVariant data1 =;
           const QVariant data2 =;
           const int difference = data1.toInt() - data2.toInt();
           return difference;
        return QSqlTableModel::data(index, role);


    QVariant headerData(int section, Qt::Orientation orientation, int role) const
    if (orientation == Qt::Horizontal && section == DifferenceColumn)
    return tr("Difference");

      return QSqlTableModel::headerData(section, orientation, role);


    Dialog::Dialog(QWidget *parent) :
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");

    QSqlQuery query;
    query.exec("create table datas (data1 int, data2 int)");
    for (int i = 0; i < 10; ++i)
        query.prepare("INSERT INTO datas VALUES (:data1, :data2)");
        query.bindValue(":data1", qrand() % 100);
        query.bindValue(":data2", qrand() % 100);
    QHBoxLayout *layout = new QHBoxLayout(this);
    QTableView *view = new QTableView;
    MyCustomModel *model = new MyCustomModel(this);


    When I was subclassing QSortFilterProxyModel, all the indexes refering to the additional column we created were invalid.

  • Awesome!

    Thanks so much for working that out, octal. I just finished getting the example above working and it does so perfectly!

    Next, I will give it a shot with the real code.

    Thanks again for your help.

  • Still, as a side note, it is very much possible to do this using a proxy model. That makes the code reusable with any underlying model that you may wish to use with it.

    Note: /me is a fan of proxy models :-)

  • @Andre, thanks for the tip!

    I've almost gotten it to work using the proxy model.

    The weird thing is, that the new column shows and displays the correct field name and value (the difference,) but after I update one of the values in the table the difference column disappears.

    Any ideas? It removes the column if I use either QSortFilterProxyModel or my subclass.


  • Using the modeltest class to test your (proxy) model is usually a great help to find the problems that underly symptoms like these. Did you use it?

  • No, I didn't. I have not heard of that before.

    I just found it mentioned "here":, though:

    I'll give that a shot and see what happens.


  • Hmm. Do I have to sign up with gitorious to get these files?

    I can click in them and copy out the text and create my own files, since there's not many. For some reason it doesn't give me the choice to just download them in Opera on Linux. This is the first time I've dealt with files on a gitorious (or git) server.

  • I cut and pasted the modeltest source files, this morning. I'll get to test with them tonight, hopefully.

    Update --20110913_1249--
    I just figured out the download thing. I just need to click on the "Raw blob data". Heh, wish I would have seen this sooner. I'm an idiot.

    Also, the link to "Model Test": says to include the modeltest.pri file inside of my project's pro file, but there was no .pri file in the repository. I'm going to assume that means to rename to modeltest.pri and include that.

  • bq. I’m going to assume that means to rename to modeltest.pri and include that.

    Personally, that's what I do when I use the ModelTest. Now have fun debugging your model :)

  • Will do. Thanks!!!

  • Well, I didn't have any asserts occur with ModelTest, but maybe I used it wrong.

    To use it I:

    copied the files to a seperate folder.

    modified the .pro to be .pri

    included the new .pri file into my .pro file via:


    removed all sources and headers from the .pri file except modeltest.h and modeltest.cpp

    added a line for QT += test

    comment out the load(qttest_p4) line because of the following warning:

    @WARNING: /home/jetimms/code/Qt/cashflow_01.nix/modeltest.pri:1: Unable to find file for inclusion qttest_p4@

    in the same code that I instantiated my proxy model, I included modeltest.h and added the following line just after creating its instance:

    @new ModelTest(balanceProxyModel, this);@

    I did see these debug messages, but I don't recognize them from my stuff. They occur when a change to the view is entered.
    Debug: ratbr QModelIndex(-1,-1,0x0,QObject(0x0) ) 0 128
    Debug: rr QModelIndex(-1,-1,0x0,QObject(0x0) ) 0 128

  • I had so many Debug messages coming through, that I didn't realize that the two mentioned above were not one of mine :)

    The source file modeltest.cpp clued me into what those messages meant:
    ratbr - rowsAboutToBeRemoved() pushes onto a QStack the index info in rows 0 through 128 that are about to be removed
    rr - rowsRemoved() compares rows 0 through 128 that were removed to those on top of QStack and asserts if they differ

    What is puzzling to me is why it would be removing any rows, much less 129 of them. By the way, my table contains 129 records.

    The view still shows all of my rows so none are missing after the debug message. This removal could be a function of the sort that defaults to the first column, though. I'll try the ModelTools using QSortFilterProxyFilter and see what happens.

    However, the two functions mentioned above only look at only column 0 (see the following snippet from rowsAboutToBeRemoved()):

    The below is with start = 0, end = 128, and Changing is a simple structure
    Changing c;
    c.parent = parent;
    c.oldSize = model->rowCount ( parent );
    c.last = model->data ( model->index ( start - 1, 0, parent ) ); = model->data ( model->index ( end + 1, 0, parent ) );

    This is strange because my difference column (the one I added) is the 7th column of the view.

    Perhaps the QModelIndex that is referred to is just an index for my difference column and not the entire model's scope. Maybe its the proxy model's scope since it would only contain a column 0, the difference column. It is the model that I added the column to, after all.

    One more mystery is that the ratbr and rr messages occur after each edit submission, not just the first one.

    I'll keep digging.

  • octal,
    While trying to debug my model, I move line 29 and 30 from your first example:

    const QSqlTableModel *model = qobject_cast<const QSqlTableModel *>(sourceModel());

    to just above the if block that it was in and got an assert on the model being NULL. I've tried in the other functions provided to copy the same code, but the only other one it works in is headerData.

    Any idea of why that happens? Just curious because I saw no reason.

  • I also found "this bug report": which wasn't fixed until 4.7.2. The report specifies QSqlTableModel, but says nothing about QSortFilterProxyModel.

    I suspect that its related, anyhow, to my disappearing columns.

    Mepis 11 (my Linux distro of choice) only has 4.7.1-2 of libqtcore4 available in its repository. I'm thinking about downloading the source and configuring the libraries myself.

    [EDIT: fixed link, Volker]

  • Just tried this on an install of Qt libs version 4.7.2 built on a Windows XP Pro x64 box at work.

    I got the same results when I ran my code using the subclass of the QSortFilterProxyModel which sources a populated QSqlTableModel.

    The difference column (read-only) appears with the correct amount in it at first. After an edit to the view, it disappears.

    So Qt libs 4.7.2 didn't fix my issue.

    Upon further inspection, the bug mentioned above does not specify a proxy model being used, just the QSqlTableModel and its call to QSqlQueryModel.

  • I wizened up and cut and paste octal's latest demo subclass of QSqlTableModel into my own, changed the number of columns, got rid of the proxy model and it worked!

    I would like to know how to get the proxy model to add the column, but my original problem is solved. Now, I can continue with the app.

    Thanks for the help, octal and Andre!

  • Hi jetimms,

    Could you send the code snippet which use QSortFilterProxyModel subclassing to add the custom column addition.
    I can't realize the index problem that octal mentioned.


    [quote author="jetimms" date="1315884755"]@Andre, thanks for the tip!

    I've almost gotten it to work using the proxy model.

    The weird thing is, that the new column shows and displays the correct field name and value (the difference,) but after I update one of the values in the table the difference column disappears.

    Any ideas? It removes the column if I use either QSortFilterProxyModel or my subclass.


  • @tombalak,

    I ended up basing my solution (almost exactly) from octal's code that subclassed QSqlTableModel after getting his to work in a sample. When I used QSortFilterProxyModel to subclass, any created columns would disappear after changing and submitting the values of one of them. I'm not sure that my issue was with the indexes either.

  • thanks jetimms,

Log in to reply