Jongling Qt models

When you work intensively with data in your application then soon or not but you will realize that the best way of keeping them is some model object inherits from QAbstractItemModel, then data are hidden inside implementation of model. Adding, removing and modification are accessible through your API of the model class and it calls for appropriate model modifications (like beginInsertRows/endInsertRows). If you implement it in the way, then it is ideal for developer to use it in vews, operate with datas, implementing undo (see previous post: Undo in complex Qt projects).

It is often situation when all application data are some kind of hierarchical tree of objects and properties. So, all of them can be kept in just one tree-like model class, but I see that developers do not use the approach and it happens because they do not see how some selective piece of data can be shown or have expectations of implementing own view classes, which is not trivial though and you may spent too much efforts there. Instead a lot of code related to synchronization between models can appear and it leads to complication of logic.

Same time, it can be resolved by implementation proxy models and use just standard view classes from Qt which are very effective. And I would like to show here that it is really simple:

There is simple example that I had to implement recently. The application shows list of objects, and same time it should show list of all properties of all objects. My first impression was to implement two separate models that may have shared data or base data are kept in one of model + some synchronization. But I saw that data manipulations leads to code complication + undo should be implemented smoothly.

We can implement just one model which is tree of objects (two levels). In one view (we can use QListView to show only first level of tree) we show listed objects. But what about another view to list of all objects of second level – we can implement proxy model which will be model of view

ProxyModel

Let’s have a look at QAbstractProxyModel. For mapping we need the implementation of mapFromSource() and mapToSource() plus rowCount / columnCount() / parent() and index().
Because destination model is table-like, parent() returns just QModelIndex(), columnCount() returns count of source model, and index() returns just createIndex(row, column).
More complex are rowCount(), mapFromSource() and mapToSource() because they need to calculate. (see a listings below)

Another piece of logic – appropriate behavior on adding /removing rows and data changes. QAbstractItemModel has very convenient signals reporting process of adding rows or columns. With recalculating indexes we can just call same methods of proxy models, like:


...
connect(source, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), 
        this, SLOT(s_rowsAboutToBeInserted(QModelIndex, int, int)));
connect(source, SIGNAL(rowsInserted(QModelIndex, int, int)), 
        this, SLOT(s_rowsInserted(QModelIndex, int, int)));
...

void Proxy::s_rowsAboutToBeInserted(QModelIndex p, int from, int to)
{
    if (!p.isValid()) 
        return;

    int f = ... // calculate
    int t = ... // calculate
    beginInsertRows(QModelIndex(), f, t);
}

void Proxy::s_rowsInserted(QModelIndex p, int, int)
{
    // post adding routines if needed
    endInsertRows();
}

So, to summarize: it is not much efforts to implement proxy model which do appropriate data mappings in both directions. As benefit you have data kept in one place, all necessary signals by model to report changes in data (model). By mapping / proxying / filtering you can visualize in view any piece of data, even from different levels of hierarchy, etc. To visualize you can use just standard Qt view which are very effective.

Full listings of my proxy model:

UngroupProxyModel.h
UngroupProxyModel.cpp

Update:
Read also Jongling Qt models 2, Composition Gem

This entry was posted in Blog, Models, Qt, Research. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

4 Comments

  1. Valery
    Posted August 5, 2011 at 07:55 | Permalink

    UngroupProxyModel::mapFromSource() is not correct!!! Please patch this function

  2. sajjad
    Posted April 3, 2012 at 17:24 | Permalink

    Hi

    Could provide some hint of the necessary changes that i need to make if i need to ungroup every item in the model, all parents and its children under one parent – QModelIndex() ?

    Regards
    Sajjad

  3. yshurik
    Posted April 3, 2012 at 19:40 | Permalink

    sajjad: are about UngroupProxyModel? then have a look at attached files – UngroupProxyModel.cpp

  4. flowsens
    Posted November 3, 2017 at 13:40 | Permalink

    Hi,

    Is the posted code supposed to work and be complete ?
    Because the posted code does not compile for me with Qt5.6.2.
    In UngroupProxyModel.cpp::L101 and L222 a method named reset() is called. This method is not defined. In case this line of code refers to QAbstractItemModel::reset(), the problem is that the member reset() is protected in that class.
    Is there a newer version of the source code.
    Cheers

2 Trackbacks

  1. By Jongling Qt models 2, Composition Gem on September 19, 2011 at 13:47

    […] programming. Especially due to proxies to do filtering, sorting or even rearranging data (see Jongling Qt models) to be organized in any way that is good for you. You can have one data source model which you then […]

  2. […] proxy which does item rearrangements like ungrouping proxy (example: http://lynxline.com/jongling-qt-models/) should implement support of […]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>