Display data from QAbstractTableModel in QTreeView

烂漫一生 提交于 2019-11-29 16:02:07

From the official documentation:

When implementing a table based model, rowCount() should return 0 when the parent is valid.

The same goes for columnCount(). And for completeness, data() should return None if the parent is valid.


What happened is this:

  1. You click on the '+' sign next to "Stinkberries".
  2. The QTreeView thinks, "I need to expand the view. I wonder how many rows exist under 'Stinkberries'?" To find out, the QTreeView calls rowCount(), and passes the index of the "Stinkberries" cell as the parent.
  3. FavoritesTableModel::rowCount() returns 5, so the QTreeView thinks, "Ah, there are 5 rows under 'Stinkberries'."
  4. The same process happens for columns.
  5. The QTreeView decides to retrieve the first item under "Stinkberries". It calls data(), passing Row 0, Column 0, and the index of the "Stinkberries" cell as the parent.
  6. FavoritesTableModel::data() returns "Apples", so the QTreeView thinks, "Ah, the first item under 'Stinkberries' is 'Apples'."
  7. etc.

To get correct behaviour, your code must return 0 for Steps #3 and #4.


Finally, to make sure that the '+' signs don't appear at all, make hasChildren() return false for every cell.

Solution

In theory, a nice feature of the Model-View framework is that you can have multiple views of the same Model. In practice, though, QAbstractTableModel is really meant to help you view tables, not trees. The documentation for QAbstractTableModel says:

Since the model provides a more specialized interface than QAbstractItemModel, it is not suitable for use with tree views

However, even given that caveat, there is a way to get this to work. First, as pointed out by JKSH, you have to fix rowCount (and note that its second parameter is a parent index):

def rowCount(self, parent=QtCore.QModelIndex()):
    if parent.isValid():
        return 0
    return len(self.foods)

Second, remove the quixotic reimplementation of index, which was making the selection behavior act really weird for reasons I frankly don't understand.

In general, though, if you want a generic model then play it safe and subclass from QAbstractItemModel instead of one of the pre-made models.

Discussion

Ignoring the parent within rowCount is acceptable in table models. In the official Qt book, they follow the standard procedure of having rowCount returning solely the number of rows to be displayed in the table. Blanchette and Summerfield note:

The parent parameter has no meaning for a table model; it is there because rowCount() and columnCount() are inherited from the more generic QAbstractItemModel base class, which supports heirarchies. (p 255)

In his PyQt book, Summerfield notes:

[T]he parent QModelIndex p matters only to tree models (p 434)

Basically, rowCount tells you how many rows to display underneath a parent item. Because in tables all items have the same parent, the parent item is not used in QTableViews. But for reasons pointed out very nicely by JKSH in his answer, this strategy won't work with trees.

Hence, the claim that the parent parameter "has no meaning for a table model" should be modified with the qualification that this is only true if the data will exclusively be displayed by a QTableView (which is usually a pretty good assumption).

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!