PDA

View Full Version : How to stop calling data() function for the child items in a tree view initially



DURGAPRASAD NEELAM
8th May 2015, 15:03
Hi,
I am implementing a tree view where initially I am showing all the parents, all the child items are collapsed.
but when initially I show my tree view, data() function is calling for all the items which are collapsed(childs) also.
How to prevent the data function calling for collapsed child items also, I want my data function to be called only for the items which are visible.

I have customized QAbstractItemModel, QTreeView and using them.

Thanks in advance.

wysota
9th May 2015, 00:10
I have customized QAbstractItemModel, QTreeView and using them.

How are we supposed to help if we don't know what you had customized?

DURGAPRASAD NEELAM
9th May 2015, 12:27
I have re-implemented below functions in my model.



QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const ;
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
Qt::ItemFlags flags( const QModelIndex &index ) const;
QVariant headerData( int section, Qt::Orientation orientatio, int role = Qt::DisplayRole ) const;
virtual QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const;
virtual QModelIndex parent( const QModelIndex &index ) const;
int rowCount( const QModelIndex &parent = QModelIndex() ) const;
virtual bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const;
int columnCount( const QModelIndex &parent = QModelIndex() ) const { return m_columnCount; }

And I am using proxy model too for filtering data, here i re-implement filterAcceptsRow().
If more info is needed, Please let me know.

Thnaks.

wysota
9th May 2015, 17:22
Yes, more info is needed :)

DURGAPRASAD NEELAM
9th May 2015, 19:04
here is the implementation Part of Model.
if more info is needed, Please let me know exactly what is needed :-)

Note : Entire implementation (model, Item) is from Sample tree model example in Qt only (It fits for my requirement so, I just edited that example)

//proxy


ProxyModel::ProxyModel( QObject *parent ): QSortFilterProxyModel( parent )
{
setDynamicSortFilter( false );
}
ProxyModel::~ProxyModel()
{
}
bool ProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
{
return filterLogic();
}



//Model

Model::Model(const QList<QList<QVariant> > &lines,const QList<int>& positions)
{
QList<QVariant> rootData;
m_rootItem = new Item( rootData );
setupModelData( lines, positions, m_rootItem );
}

Model::~Model()
{
delete m_rootItem;
}

Item* Model::getRootItem() const
{
return m_rootItem;
}

QVariant Model::data( const QModelIndex &index, int role ) const
{
if ( ! index.isValid() )
return QVariant();

Item *item = static_cast<Item*>( index.internalPointer() );
switch( role )
{
case Qt::DisplayRole:
{
return item->data( index.column(),Qt::DisplayRole );
break;
}
}
return QVariant();
}

bool Model::setData( const QModelIndex &index, const QVariant &value, int role )
{
if (( role != Qt::EditRole && role != Qt::DecorationRole && role != Qt::ForegroundRole && role != Qt::BackgroundRole ) || !index.isValid() )
return false;

/* Get the item of this index */
Item *item = static_cast<Item*>( index.internalPointer() );

/* Editing this item */
bool result = item->setData(index, value, role);

if (result)
emit dataChanged( index, index );

return result;
}

Qt::ItemFlags Model::flags( const QModelIndex &index ) const
{
if ( ! index.isValid() )
return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}

QVariant Model::headerData( int section, Qt::Orientation orientation, int role ) const
{
if ( orientation == Qt::Horizontal && role == Qt::DisplayRole )
{
return m_rootItem->data( section,Qt::DisplayRole );
}
return QVariant();
}

QModelIndex Model::index( int row, int column, const QModelIndex &parent ) const
{
if ( ! hasIndex(row, column, parent) )
return QModelIndex();

Item *parentItem;
if ( ! parent.isValid() )
parentItem = m_rootItem;
else
parentItem = static_cast<Item*>( parent.internalPointer() );

Item *childItem = parentItem->child( row );
if ( childItem )
return createIndex( row, column, childItem );
else
return QModelIndex();
}

QModelIndex Model::parent( const QModelIndex &index ) const
{
if ( ! index.isValid() )
return QModelIndex();

Item *childItem = static_cast<Item*>( index.internalPointer() );
Item *parentItem = childItem->parent();

if ( parentItem == m_rootItem )
return QModelIndex();

if( parentItem == NULL )
{
return QModelIndex();
}
return createIndex( parentItem->row(), 0, parentItem );
}

int Model::rowCount( const QModelIndex &parent ) const
{
Item *parentItem;
if ( parent.column() > 0 )
return 0;

if ( ! parent.isValid() )
parentItem = m_rootItem;
else
parentItem = static_cast<Item*>( parent.internalPointer() );

return parentItem->childCount();
}

bool Model::hasChildren ( const QModelIndex & parent ) const
{
Item *parentItem;
if ( parent.column() > 0 )
return false;

if ( ! parent.isValid() )
parentItem = m_rootItem;
else
parentItem = static_cast<Item*>( parent.internalPointer() );

return parentItem->hasChildren();
}

void Model::setupModelData(const QList<QList<QVariant> >& lines, const QList<int>& positions, Item *parent)
{
//same logic from Sample tree example in Qt
}

wysota
9th May 2015, 20:31
If you want to nail down the problem then get rid of all elements that do not change the test result. If it still doesn't work without a proxy model then remove it from the equation and repeat the test. Find a minimal compilable example reproducing the problem. You said you modified the view and the model. Can you reproduce the problem using a custom model with a standard view? How about a standard model and customized view?

DURGAPRASAD NEELAM
9th May 2015, 20:59
hmm.. I will try those things and let you know the result.
mean while, with your experience do you have any idea or can you suspect any of the functions which might cause for this problem.

Note :: I am doing some another thing in Data actually, Will this cause any problem ??


QVariant Model::data( const QModelIndex &index, int role ) const
{
if ( ! index.isValid() )
return QVariant();

Item *item = static_cast<Item*>( index.internalPointer() );
switch( role )
{
case Qt::DisplayRole:
{

//initially i am getting data which is needed for building empty tree, then i am populating that empty tree
// on demand, when data function called I am reading data from Data base and updating Item data and then reading it


1. read data from data base //read one row from db
2. item->setData(data); // update that data to item

//then read ite
return item->data( index.column(),Qt::DisplayRole );
break;
}
}
return QVariant();
}

wysota
9th May 2015, 23:05
No, I don't think so.

DURGAPRASAD NEELAM
10th May 2015, 21:10
I could not found a reason for this problem, so I have implemented a logic

1. if data is called for an item, I am checking weather it is child or not, if it is child item then I am checking its parent is expanded or not
If it parent is expanded then I am firing a query to read a data from data base otherwise not firing a query as we are not showing it in a view (item is collapsed).
2. when we expand an item, data function should be called then I am again I am checking parent is expanded or no, this time it will be true then I am firing a query and getting data.

But strangely When I expand an item (Click on + sign ), data() function will not be calling at all :-(
When I remove proxy model then data function is calling (when clicks on + sign).

What is this strange behavior, why data function is not calling when proxy is there in above case ??




QVariant TreeModel::data( const QModelIndex &index, int role ) const
{
if ( ! index.isValid() )
return QVariant();

TreeItem *item = static_cast<TreeItem*>( index.internalPointer() );
switch( role )
{
case Qt::DisplayRole:
{
TreeItem* l_parent = item->parent(); //parent item

bool l_getData = true;

if(m_rootItem == l_parent) // if top most item then we should read data
{
l_getData = true;
}
else if(l_parent && !l_parent->isExpanded()) //if its not top most item and its parent is not expanded, no need to read data
{
l_getData = false;
}


if(l_getData && !item->isDataUpdated()) // if data need to be read
{
ReadRowFromDb(index); // read from Data base & update item
}

return item->data( index.column(),Qt::DisplayRole ); // then read data from item
}
}
}

d_stranz
10th May 2015, 22:20
What is this strange behavior, why data function is not calling when proxy is there in above case ??

Most likely you have not implemented the mapping functions in your proxy model, or you have implemented them incorrectly. Did you implement the data() method in the proxy?

DURGAPRASAD NEELAM
11th May 2015, 06:41
The only function I have implemented in customized QSortFilterProxyModel is filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const.
I have not implemented the data() function.

What are the function I should to re implement while using proxy?

Thanks in Advance.

DURGAPRASAD NEELAM
11th May 2015, 15:01
I have implemented data() in proxy too, still same issue.




QVariant proxy::data(const QModelIndex & proxy_index, int role) const
{
if ( ! index.isValid() )
return QVariant();

QModelIndex source_index = mapToSource(proxy_index);

return QSortFilterProxyModel::data(proxy_index, role);
}

wysota
11th May 2015, 15:18
Try minimizing your example instead of throwing in more and more code. Can you reproduce the issue with a bare standard item model and a bare QTreeView?

DURGAPRASAD NEELAM
12th May 2015, 10:59
When I tried using with QTreeView only, data function is calling as expected.

wysota
12th May 2015, 11:11
When I tried using with QTreeView only, data function is calling as expected.

So please show your customizations to the view.

DURGAPRASAD NEELAM
12th May 2015, 22:34
Below is the code for view. (there is lot of other c++ code in view, but typical qt related stuff in view is this much)


MyView::MyView ( Model* treeModel) : QTreeView(parent)
{
setContextMenuPolicy( Qt::DefaultContextMenu );
setSelectionMode( QAbstractItemView::ExtendedSelection );
setSelectionBehavior( QAbstractItemView::SelectItems );
installEventFilter( this );

m_proxyTreeModel = new ProxyModel( this ); // proxy model:
m_proxyTreeModel->setSourceModel( m_treeModel ); // tree model created in viewer:
m_proxyTreeModel->setDynamicSortFilter(true);
setModel( m_proxyTreeModel );

setAllColumnsShowFocus( true );
setUniformRowHeights( true );
}

wysota
12th May 2015, 22:46
This is not your real code. This wouldn't even compile. Even if it did, it would crash when ran. And you were supposed to use a standard model against your custom view. Without any proxy models inbetween.