Using QTreeView with QAbstractItemModelVirgil Dupras2009-09-26 For someone coming from the Cocoa world, understanding how The biggest difference between the two models is in the way they refer to cells. In Cocoa, we use an arbitrary identifier supplied by the model through To a Qt newbie, this requirement for the model to return redundant data (row and column) might seem stupid. They might even think that it's downright insane when they discover that subclassing It turns out that there's a reason for this strange and complex API: TrollTech over-engineered this part of the toolkit. They wanted to design their item model so that it would be possible for a single model instance to have table views and tree views connected to it at the same time. While I'm sure that there are cases where this feature is very useful, there's a lot of What to do?While Alright, let's get to it. Typically, what we have is an internal structure of elements organized in a tree structure. We want the tree view to display our elements using the same internal organization, and for each element, we want to display some data in each columns of the tree view. In a sane tree model system, you could, most of the time, directly use the element instance as an "internal reference" (a reference to an instance that the tree view keeps and supplies back to the model in its calls. So, what do we do? We create a wrapper around each element. Let's call it class TreeNode(object): def __init__(self, parent, row): self.parent = parent self.row = row self.subnodes = self._getChildren() def _getChildren(self): raise NotImplementedError() It might seem very basic, but remember that all we want to deal with is the class TreeModel(QAbstractItemModel): def __init__(self): QAbstractItemModel.__init__(self) self.rootNodes = self._getRootNodes() def _getRootNodes(self): raise NotImplementedError() def index(self, row, column, parent): if not parent.isValid(): return self.createIndex(row, column, self.rootNodes[row]) parentNode = parent.internalPointer() return self.createIndex(row, column, parentNode.subnodes[row]) def parent(self, index): if not index.isValid(): return QModelIndex() node = index.internalPointer() if node.parent is None: return QModelIndex() else: return self.createIndex(node.parent.row, 0, node.parent) def reset(self): self.rootNodes = self._getRootNodes() QAbstractItemModel.reset(self) def rowCount(self, parent): if not parent.isValid(): return len(self.rootNodes) node = parent.internalPointer() return len(node.subnodes) Now that your base class NamedElement(object): # your internal structure def __init__(self, name, subelements): self.name = name self.subelements = subelements class NamedNode(TreeNode): def __init__(self, ref, parent, row): self.ref = ref TreeNode.__init__(self, parent, row) def _getChildren(self): return [NamedNode(elem, self, index) for index, elem in enumerate(self.ref.subelements)] class NamesModel(TreeModel): def __init__(self, rootElements): self.rootElements = rootElements TreeModel.__init__(self) def _getRootNodes(self): return [NamedNode(elem, None, index) for index, elem in enumerate(self.rootElements)] def columnCount(self, parent): return 1 def data(self, index, role): if not index.isValid(): return None node = index.internalPointer() if role == Qt.DisplayRole and index.column() == 0: return node.ref.name return None def headerData(self, section, orientation, role): if orientation == Qt.Horizontal and role == Qt.DisplayRole \ and section == 0: return 'Name' return None This is, of course, very basic, and if you actually use a |
|
|
This site is best viewed with Opera while listening to The White Stripes |
|