[Qt-interest] ModelView - how to use proxies to filter this data?

Daniel Price daniel.price at fxhome.com
Tue Dec 1 16:36:18 CET 2009


Thanks for the info. I hadn't considered using a proxy filter and just accepting/rejecting rows. Does that work with hierarchical data though?

I actually QAbstractProxyModel and implemented the mapTo/mapFrom functions. But sorting doesn't seem to work.

BTW it looks like you're storing pointers to your structures in your variants as integers and casting them back. You don't need to do this. Register your class/struct type with Qt's metadata system and then use QVariants templated value() function to get the pointer back. Clean and safe. Eg:

struct Product
{
        QString name;
        float price;
};

Q_DECLARE_METATYPE(Product*);

m_modelAdaptor->setData(m_modelAdaptor->index(0,0,productRootIndex),variantForType< Product *>(product));

....

Product *ptr = data(0,0, productRootIndex).value<Product*>();

I wrote this function to simplify the process of getting pointers into variants:

template <typename T>
QVariant variantForType(const T& data)
{
        QVariant var;
        var.setValue(data);
        return var;
}


> -----Original Message-----
> From: qt-interest-bounces at trolltech.com [mailto:qt-interest-
> bounces at trolltech.com] On Behalf Of Sean Harmer
> Sent: 01 December 2009 11:45
> To: qt-interest at trolltech.com
> Subject: Re: [Qt-interest] ModelView - how to use proxies to filter
> this data?
>
> 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.
>
> No virus found in this incoming message.
> Checked by AVG - www.avg.com
> Version: 9.0.709 / Virus Database: 270.14.87/2535 - Release Date:
> 11/30/09 21:05:00

This email is confidential. It may also be privileged or otherwise protected by work product immunity or other legal rules. If you are not the intended recipient please notify the sender. Please delete the message from all places in your computer where it is stored. You should not copy the email or use it for any purpose or disclose its contents to any other person.To do so may be unlawful. Email is an informal means of communicating and may be subject to data corruption accidentally or deliberately. For this reason it is inappropriate to rely on advice contained in an email without obtaining written confirmation of it first.

FXhome Limited is a limited company registered in England and Wales. Registered number: 04172812. Registered office: The Henderson Business Centre, Ivy Road, Norwich, Norfolk, NR5 8BF, U.K.




More information about the Qt-interest-old mailing list