PDA

View Full Version : Restructuring a QTreeView



tgoetz
17th May 2017, 20:17
[SIZE=2]Hello,

I'm using QTreeView with a QAbstractItemModel to display my data in a hierarchical tree. Each object has a couple of properties like owner and type and I'm using these properties to create dummy items in my tree to group the data, like this:



root

- type_1


- object_1


- object_2

- type_2


- object_n


Now the user should be able to re-group the data, i.e. by owner not type like this:



root

- owner_1


- object_2


- object_3

- owner_2


- object_1


I have added a resortTree(mode) method to my AbstractItemModel class and the class also contains a std::vector of pointers to the object that is used to fill the tree the first time it is generated.

[SIZE=2]
class DatasetTreeModel: public QAbstractItemModel
{
Q_OBJECT

public:

enum TreeSortMode
{
DatasetType = 0,
DatasetOwner = 1,
DatasetCreation = 2,
};

DatasetTreeModel(std::vector<Dataset*> _data, TreeSortMode = DatasetType, QWidget* _pParent = NULL);

~DatasetTreeModel();

...

void resortTree(TreeSortMode = DatasetType);

private:

std::vector<Dataset*> m_vDatasets;
}

The implementation looks like this:


void DatasetTreeModel::resortTree(TreeSortMode _sorting)
{
switch (_sorting)
{
case DatasetType:
{
// creates dummy parent items for the actual objects
for (int j = 0; j < (int) Dataset::NumberOfTypes; j++)
{
m_pRootItem->insertChildren(m_pRootItem->childCount(), 1);
m_pRootItem->child(m_pRootItem->childCount() - 1)->setName(Dataset::typeToString((Dataset::DatasetTyp e) j));
m_pRootItem->child(m_pRootItem->childCount() - 1)->setType(Dataset::undefined);
}

// inserts the actual objects as children to the matching dummy parents
for (int i = 0; i < m_vDatasets.size(); i++)
{
Dataset::DatasetType type = m_vDatasets[i]->getType();
DatasetTreeItem* parent = m_pRootItem->child(type);
if (!parent->insertChildren(parent->childCount(), 1))
{
std::cerr << "Error inserting child into Dataset tree" << std::endl;
}
if (!parent->child(parent->childCount() - 1)->setDataset(m_vDatasets[i]))
{
std::cerr << "Error inserting Dataset object into DatasetTreeItem" << std::endl;
}
}
break;
}
case DatasetOwner:
{
...
}
}
}


The method works well when I call it the first time. However, when I call the method again, I get an memory access error because the std::vector with the objects somehow got corrupted. I can't find any place where this corruption can happen, however, all activities on it are read-only with one single exception:



DatasetTreeModel::DatasetTreeModel(std::vector<Dataset*> _data, TreeSortMode _sorting, QWidget* _pParent)
: QAbstractItemModel(_pParent)
{
m_pRootItem = new DatasetTreeItem(QString("%1 Files").arg(_data.size()));
m_pRootItem->setType(Dataset::undefined);

m_vDatasets = _data;

resortTree(_sorting);
}

I'm not set on using this method, if there is any way to restructure a tree efficiently in the way I've described it, I'm happy to use that one.

Thanks!

d_stranz
18th May 2017, 17:33
I think if I were doing this, I'd leave the base model alone and add three proxy models, one for each DatasetType that accesses the base model in the proper sort order. When the use wants to switch types, simply change the proxy used by the view.

What you are doing works fine when you have a one-to-one relationship between model and view. If you want to be able to display the same model in different ways in different views, then messing with the base model makes this nearly impossible.

In any case, whenever you are going to radically change the model like this, you need to notify all views in advance of what is going to happen by calling beginModelReset() or a similar method, followed by modelReset() after you are done. This tells views to stop any updates and then refresh once the changes are done.

tgoetz
18th May 2017, 17:55
I'm already using a proxy to sort the leafs in the tree by creation date, changed date, and other criteria which works fine. But I don't see how that would allow me to change the top level items in my tree from lets say type to owner. I have to remove the old to level items in order to put in the new ones in and then sort the leaves back in accordingly. The three entries in the TreeSortOrder enum are only telling me about which Dataset parameter should be used as top level items. There are potentially tens of owners and also tens of types.

As with creation date, I wanted to get a structure that uses the year as top level, months as children and then sorts in the individual Datasets into the respective month.



2017

January

February

...
2016

January
...