[Qt-interest] ModelView - how to use proxies to filter this data?
Sean Harmer
sean.harmer at maps-technology.com
Tue Dec 1 12:44:43 CET 2009
Hi Daniel,
On Monday 30 November 2009 11:15:24 Daniel Price wrote:
> I need to use modelView in an advanced way.
>
> I have data like this (contrived example):
>
> People{}
> ---person1{first name, last name,address1,address2,phone, email}
> ---person2{first name, last name,address1,address2,phone, email}
> ---person3{first name, last name,address1,address2,phone, email}
> Companies{}
> ---company1{name, address1, address2,phone,website}
> ------product1{name,type,price}
> ------product2{name,type,price}
> ---company2{name, address1, address2,phone,website}
> ------product1{name,type,price}
> ------product2{name,type,price}
> The data is hierarchical but sub-categories of data have different columns
> and different data for each column. In the above example, 'person' records
> have 6 columns, but 'product' records have 3. The actual data I'm dealing
> with is a lot more complex.
OK we have something similar to this, although not quite as complex. In our
case each of our leaf nodes has the same number and type of columns.
> Now an QAbstractItemModel-derived class can be used as an adaptor for this
> but the data cannot (practically) by displayed within a QTreeView. So my
> idea is to use QAbstractItemProxy-derived classes to wrap the model. The
> primary single-column TreeView will display the following as headers:
>
> People
> ---person1
> ---person2
> ---person3
> Companies
> ---Company1
> ---Company2
>
> When a Person or Company row is selected, a secondary TableView with
> display the data, stored as child indexes of that item in the original
> model.
This is basically what we do. However we take advantage of the
QSortFilterProxy model to do the heavy lifting for us. This turns out to be
really quite simple to do. See the attached mapsdata1dtreeproxymodel.{h,cpp}
files. You only need to override the 3 virtual functions:
QVariant headerData( int section, Qt::Orientation orientation, int role )
const;
bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const;
bool filterAcceptsColumn( int sourceColumn, const QModelIndex& sourceParent )
const;
as shown. The idea is that the filter only accepts a row/column if it is a
grouping node. The headerData() function just allows us to provide a
specialised label(s) for the headers i.e. Channel/Frequency or Artist/Album
etc.
> So I would need four models - the original (invisible) model with all the
> data, an Overview proxy model for the primary tree, a Person proxy model,
> and Company proxy model.
Yes but I think that you can also use a subclass of QSortFilterProxyModel for
your proxies. Again you just need to override the same 3 functions as
appropriate.
> I'm having trouble implementing this due to the lack of
> examples/information available. Here is what I have discovered:
>
> 1) It looks like QAbstractProxyModel-derived classes must propagate
> all signals emitted by the source model or it will do nothing (the
> examples I've seen work only on static data created before the model is
> hooked up so it does not matter).
>
> 2) From studying the QSortFilterProxyModel implementation, it seems
> that proxies cannot share indexes from the source model - they must create
> their own.
>
> I just need to be able to pick out the data from the primary model for each
> view. Does anyone have examples on how to proceed? No-one seems to have
> done this publically outside of Nokia so information is rare!
One other thing that I have knocked together to make my life easier is a so-
called SplitView widget that consists of a QTreeView and a QTableView housed
in a QSplitter. This allows the client of the class to set an overall model
and a "Category" model. The "Category" model is our filtered tree model as
described above that only shows the group nodes.
When the user clicks on a group node in the tree view, there is a slot that
then takes care of setting the model and the appropriate rootIndex on the
QTableView for showing the actual detail of the model. This is how I do this:
void SplitView::setTableView( const QModelIndex& index )
{
// Check with the category model to see if this index has children or not
bool hasChildren = m_categoryModel->hasChildren( index );
if ( !hasChildren )
{
// No children so we can display the (hidden) children in the
// detail table view
QModelIndex sourceIndex = m_categoryModel->mapToSource( index );
m_ui->m_tableView->setModel( m_model );
m_ui->m_tableView->setRootIndex( sourceIndex );
m_ui->m_tableView->resizeColumnsToContents();
m_ui->m_tableView->resizeRowsToContents();
}
else
{
// Don't show anything for categories with children
m_ui->m_tableView->setModel( 0 );
}
}
This is attached in the files splitview.{h,cpp}. You would need to extend this
concept slightly to take into account the fact that you will have different
proxies for each type of leaf node data. Although I suppose you could have a
single proxy for all leaf node types but just switch it into different "modes"
as needed.
> I can think of discrete ways of doing the same thing without proxies but
> having everything in a primary model has certain advantages (simplified
> undo for example).
Yes I would stick with the one model to rule them all approach and filter it as
needed.
HTH,
Sean
ps This is just some simple code I have been playing around with to try out
this idea. It is not production ready by any means and the models are read-
only in my case.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mapsdata1dtreeproxymodel.h
Type: text/x-chdr
Size: 553 bytes
Desc: not available
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20091201/d75c0d5a/attachment.bin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mapsdata1dtreeproxymodel.cpp
Type: text/x-c++src
Size: 1077 bytes
Desc: not available
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20091201/d75c0d5a/attachment-0001.bin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: splitview.h
Type: text/x-chdr
Size: 589 bytes
Desc: not available
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20091201/d75c0d5a/attachment-0002.bin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: splitview.cpp
Type: text/x-c++src
Size: 1386 bytes
Desc: not available
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20091201/d75c0d5a/attachment-0003.bin
More information about the Qt-interest-old
mailing list