August 3, 2011

Guillaume Belz Guillaume Belz
Lab Rat
16 posts

Strange behavior QTreeView

 

Hello everyone

I have some difficult to understanding how the QTreeView work with QAbstractItemModel and what functions it calls.
To test, I created a simple class that inherits from QAbstractItemModel and contains a tree (using QStandardItemModel). My class simply calls the function of QStandardItemModel. For example, for data ():

  1. QVariant TableToTreeProxyModel::data(const QModelIndex &index, int role) const
  2. {
  3.     return sourceModel()->data(index, role);
  4. }

I have overloaded functions that normally should be:

  1. QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
  2. QModelIndex parent(const QModelIndex &child) const;
  3. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
  4. int rowCount(const QModelIndex &parent) const;
  5. int columnCount(const QModelIndex &parent) const;
  6. Qt::ItemFlags flags(const QModelIndex &index) const;

I also draw my tree with a simple recursive function that uses data(), hasChildren(), rowCoun () and index() functions:

  1. void drawTree(QAbstractItemModel* tree, QModelIndex const& parent, int level)
  2. {
  3.     QString s = "";
  4.     QString t = s.rightJustified(level*2, ' ');
  5.     qDebug() << t + tree->data(parent).toString();
  6.     if (tree->hasChildren(parent))
  7.     {
  8.         for (int row = 0; row  < tree->rowCount(parent); ++row )
  9.         {
  10.             drawTree(tree, tree->index(row, 0, parent), level+1);
  11.         }
  12.     }
  13. }

Unfortunately, when I try to view my tree in a QTreeView, nothing is displayed (while the QStandardItemModel displayed properly).

An idea of ​​what I forgot?

thank you

PS: I also tried using a QAbstractProxyModel unsuccessfully while a QSortFilterProxyModel works.

10 replies

August 3, 2011

alexisdm alexisdm
Lab Rat
141 posts

The QModelIndex you pass as argument to sourceModel()->data() must come from sourceModel(), not from your proxy model.
So you have somehow to map your indexes to the sourceModel() indexes (that’s what mapFromSource and mapToSource are for in QAbstractProxyModel).

August 3, 2011

Guillaume Belz Guillaume Belz
Lab Rat
16 posts

Thanks for the answer

All QModelIndex was created using sourceModel() in index() function et QModelIndex::model() return the internal QStandardItemModel. I have shown only data() function but I have wrote all listed functions (index, parent, data, rowCount, columnCount and flags) with similar implementation.

I think the problem is not there (or so I did not understand)

August 3, 2011

Gerolf Gerolf
Robot Herder
3253 posts

I think, you didn’t want to implement a proxy model, right?
have a look at the Qt docs [doc.qt.nokia.com] or, if you understand German, at the German wiki [developer.qt.nokia.com]

 Signature 

Nokia Certified Qt Specialist.
Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

August 3, 2011

Guillaume Belz Guillaume Belz
Lab Rat
16 posts

Thanks

I have read the doc.

yes, it’s a proxy that I want to implement. My ultimate goal is to convert a TableModel in TreeModel using two columns of the table (one for id and one for the id of the parent). I have implemented this class, starting from QAbstractProxyModel but it didn’t work. Yet when I was testing my tree generated, it was correct. So I tried starting from QAbstractItemModel. But it did not work either. So I tried too a QAbstractItemModel which is supposed to be a simple warper of model. But this doesn’t work (this is the code that I gave).
So I guess I missed something but I can not find anything.

(I have write a class to create a new tree model from table model ans that work. But here, I want to map table and tree items)

August 3, 2011

alexisdm alexisdm
Lab Rat
141 posts

QTreeView uses some QModelIndex functions, like row()/column() or parent() and they return the index position and parent index in the source model which is flat (if I understood correctly), and not its position in your proxy model.

Can you show your implementation of rowCount ?

August 3, 2011

Guillaume Belz Guillaume Belz
Lab Rat
16 posts

Sorry, my English is not perfect and I was not necessarily clear.
My model is supposed to do anything, just call the functions of the model. And when I call the function drawTree(), the tree displays correctly. There is no position in my model proxy.

  1. QModelIndex TableToTreeProxyModel::index(int row, int column, const QModelIndex &parent) const
  2. {
  3.     return sourceModel()->index(row, column, parent);
  4. }
  5.  
  6. QModelIndex TableToTreeProxyModel::parent(const QModelIndex &child) const
  7. {
  8.     return sourceModel()->parent(child);
  9. }
  10.  
  11. QVariant TableToTreeProxyModel::data(const QModelIndex &index, int role) const
  12. {
  13.     return sourceModel()->data(index, role);
  14. }
  15.  
  16. int TableToTreeProxyModel::rowCount(const QModelIndex &parent) const
  17. {
  18.     return sourceModel()->rowCount(parent);
  19. }
  20.  
  21. int TableToTreeProxyModel::columnCount(const QModelIndex &parent) const
  22. {
  23.     return sourceModel()->columnCount(parent);
  24. }
  25.  
  26. Qt::ItemFlags TableToTreeProxyModel::flags(const QModelIndex &index) const
  27. {
  28.     return sourceModel()->flags(index);
  29. }

To create tree & proxy:

  1. // tree
  2. QStandardItem* root = tree->invisibleRootItem();
  3. QStandardItem* toto = new QStandardItem("toto");
  4. root->appendRow(toto);
  5. QStandardItem* titi = new QStandardItem("titi");
  6. toto->appendRow(titi);
  7. QStandardItem* tata = new QStandardItem("tata");
  8. titi->appendRow(tata);
  9. QStandardItem* pokemon = new QStandardItem("tutu");
  10. root->appendRow(tutu);
  11. QStandardItem* tyty = new QStandardItem("tyty");
  12. pokemon->appendRow(tyty);
  13.  
  14. // proxy
  15. proxy = new TableToTreeProxyModel;
  16. proxy->setSourceModel(tree);

To draw :

  1. drawTree(tree); // ok
  2. drawTree(proxy); // ok
  3.  
  4. QTreeView* treeView1 = new QTreeView;
  5. treeView1->setModel(tree); // ok
  6.  
  7. QTreeView* treeView2 = new QTreeView;
  8. treeView2->setModel(proxy); // not ok

August 3, 2011

Eddy Eddy
Area 51 Engineer
1612 posts

Guillaume Belz wrote:
Thanks

(I have write a class to create a new tree model from table model ans that work. But here, I want to map table and tree items)

Can you show your code for that. It should be possible to map the table and tree items through a proxy. I suppose you used a proxy for that?

 Signature 

Moderator
Qt Certified Specialist
Nokia Qt Ambassador

August 4, 2011

Guillaume Belz Guillaume Belz
Lab Rat
16 posts

I use… nothing in particular. I take a QStandardItem table for source and QStandardItem tree for destination. Conversion was performed with this :

  1. QModelIndex idRow(QAbstractItemModel* src, int row) { return src->index(row, 0); }
  2. QModelIndex parentIdRow(QAbstractItemModel* src, int row) { return src->index(row, 1); }
  3. QModelIndex titleRow(QAbstractItemModel* src, int row) { return src->index(row, 2); }
  4.  
  5. QList<int> rowByParentID(QAbstractItemModel* src, const QModelIndex &parent)
  6. {
  7.     QString id = parent.isValid() ? src->data(parent).toString() : QString("-1");
  8.     QList<int> rows;
  9.     for (int row = 0; row < src->rowCount(); ++row)
  10.     {
  11.         //qDebug() << "    row" << id << src->data(src->index(row, 1));
  12.         if (src->data(parentIdRow(src, row)) == id)
  13.             rows.append(row);
  14.     }
  15.     return rows;
  16. }
  17.  
  18. void toTree(QAbstractItemModel* src, QStandardItem* dst, QModelIndex const& parent = QModelIndex())
  19. {
  20.     QList<int> rows = rowByParentID(src, parent);
  21.     for (int row = 0; row < rows.size(); ++row)
  22.     {
  23.         QStandardItem* child = new QStandardItem(src->data(titleRow(src, rows[row])).toString());
  24.         dst->appendRow(child);
  25.         toTree(src, child, idRow(src, rows[row]));
  26.     }
  27. }
  28.  
  29. table = new QStandardItemModel(5, 3, this);
  30. tree2 = new QStandardItemModel(this);
  31. toTree(table, tree2->invisibleRootItem());

(I don’t use free functions in fact, but it’s not important here)

Problems with this approach is : data was duplicated and I must to create symetric functions to convert tree to table (if tree was modified, for update data in table)

August 4, 2011

Guillaume Belz Guillaume Belz
Lab Rat
16 posts

What I want to do has been added to Qt 4.8 (QIdentityProxyModel : http://doc.trolltech.com/4.8-snapshot/qidentityproxymodel.html)
However, this class uses the createIndex() function, which is protected (http://qt.gitorious.org/qt/qt/blobs/4.8/src/gui/itemviews/qidentityproxymodel.cpp#line259).

  1. return d->model->createIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer());

I implementing this class using the index() function, it’s work for tables but not for trees.
  1. return sourceModel()->index(proxyIndex.row(), proxyIndex.column());

I think this will work for table to tree proxy but not for symetric proxy (tree to table proxy).
If someone was ideas.
Yhanks

August 4, 2011

Gerolf Gerolf
Robot Herder
3253 posts

Hi,

I don’t know QIdentityProxyModel.
But as you only have a standard proxy model in 4.7, you have to have an index, that is created on this model and do your own mapping.
You index function may never return an index from the source model directly.

The function you mention can be called inside methods of the proxy model, e.g. for mapToSource, where it also works in 4.7.

 Signature 

Nokia Certified Qt Specialist.
Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

 
  ‹‹ [solved] to get QStandardItemModel item by key without looping using rowCount()?      What’s the best method to create a GUI similar to Qt Designer’s Property Editor? ››

You must log in to post a reply. Not a member yet? Register here!