Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Hide or unhide a section in QTreeView/Model



  • Hi,

    I have a QTreeView where a list of sections are shown based on the data I receive.
    For example

    Fruits -
    ............Apple
    ............Orange
    Animals -
    .............Lion
    .............Tiger
    Colors -
    ............Red
    ............Green
    ............BLue

    "-" = Arrow for hiding or unhiding the childrens

    The Data is read from a model (inherited from QAbstractItemModel).
    Currently While initializing the application all the Parent items ( Fruits, Animals & colors) are added to the model (root).

    Query:
    There is a possibility that sometimes I may not receive a "section" of data. For example, the entire section of Animals is not received.
    In that case I would like to Hide or remove the animal section and the result should be like

    Fruits -
    ............Apple
    ............Orange
    Colors -
    ............Red
    ............Green
    ............BLue

    I have tried one possiblity that whenever I don't receive a particular section of the data, i "remove" that particular parent item from the root before adding child items.
    Ex: root->removeItemAt(indexOfAnimal).

    So, basically I am adding or removing the section during runtime by updating the model itself.
    Is it a good idea? Does it conform with MVC ?

    Is there a better way to do this?
    Can we just hide or unhide the sections based on some condition using treeView itself?

    Section = parent + child items of a particular category.


  • Lifetime Qt Champion

    Hi,

    QSortFilterProxyModel might be your friend.

    You can use it to filter out the empty top level items.



  • Hi @SGaist ,

    Thank you for the hint.

    I started experimenting with the QSortFilterProxyModel.
    Below is the code snippet that I tried out.

    		
    bool FilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
    {
    	// check the current item
    	bool result = false;
    	QModelIndex currntIndex = sourceModel()->index(source_row, 0, source_parent);
    	if (sourceModel()->hasChildren(currntIndex)) {
    		result = true;
    	}
    	return result;
    }
    

    I want to just check if a "first level" parent has a children or not.
    But filterAcceptsRow( .. ) is recursilvely called for all the childrens.

    I want to filter/check only the first level parent because my tree view will never have second level childrens.
    It's just a single parent and single child kind of thing.

    Example:

    Color
    ........Red
    ........Green
    Animal
    ........Tiger
    ........Lion

    There is no possibility for any child ex. "Red", to have further childrens. It is more like a table.

    So, because of this I would like to apply filter only to the "parent" item (Color or Animal).
    if parent haschildren, accept parent all the childrens else do not accept anything.

    Any idea how to do that?



  • Hi,
    I tried out kind of a hack to do this.

    bool FilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
    {
    	bool result = false;
    	if (source_parent.row() != -1 || source_parent.column() != -1)
    	{
    		result = true;
    		return result;
    	}
    
    	// check the current item
    	bool result = false;
    	QModelIndex currntIndex = sourceModel()->index(source_row, 0, source_parent);
    	if (sourceModel()->hasChildren(currntIndex)) {
    		result = true;
    	}
    	return result;
    }
    

    Root seems to have row and column as -1 always.
    So, if the row or column is -1, only then the rows (parents) are filtered.
    Else (non-root parent), all are considered.

    Works as expected.
    Is this fine? Or is there a better or an even standard solution for this ?


  • Lifetime Qt Champion

    The parent being invalid means that you have a top level item.



  • bool FilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
    {
        return source_parent.isValid() || sourceModel()->hasChildren(sourceModel()->index(source_row, 0));
    }
    


  • Hello,

    Thanks a lot for the replies.

    I found out another way by which we can hide the 'section' if the parent doesn't have any childrens.
    ui.treeView->setRowHidden(parentRow, rootIndex, true)

    In my example,
    Fruits -
    ............Apple
    ............Orange
    Animals -
    .............Lion
    .............Tiger
    Colors -
    ............Red
    ............Green
    ............BLue

    Fruits is 0th parent
    Animals is 1st parent
    Colors is the 2nd parent

    So whenever any of the children's are missing ( which we come to know while filling up the model ), I am setting the respective "parent" row as hidden.
    This approach worked fine and as expected.

    Is anything wrong with this approach?
    Model remains the same, only the view is hidden or unhidden based on some condition.
    Please Let me know.


Log in to reply