On Thu, Mar 12, 2009 at 2:57 PM, Arnold Krille <arn...@arnoldarts.de> wrote:
> On Thursday 12 March 2009 17:31:40 Darren Dale wrote: > > If anybody has some example of a working QAbstractItemModel/QTreeView for > > dynamic data, would you please consider posting it (if its short) or > > sending it to me off list? I've been working on this problem for days now > > and I'm not getting anywhere. > > I don't know what you mean with dynamic data, On Thu, Mar 12, 2009 at 2:57 PM, Arnold Krille <arn...@arnoldarts.de> wrote: > On Thursday 12 March 2009 17:31:40 Darren Dale wrote: > > If anybody has some example of a working QAbstractItemModel/QTreeView for > > dynamic data, would you please consider posting it (if its short) or > > sending it to me off list? I've been working on this problem for days now > > and I'm not getting anywhere. > > I don't know what you mean with dynamic data, but I have trees that fill > themselves at runtime upon user interaction. And have children of different > kinds... > I am modeling data in a file that is organized in an hierarchy very similar to directories and files in a file system, and the structure of that hierarchy is changed not through the tree view, but elsewhere in the application. I managed to put together a workaround, based on the hasChildren/canFetchMore/fetchMore infrastructure to lazily populate the list of nodes when expanding, and connecting the TreeView collapsed signal to a method that clears the list of nodes so the list can be refreshed when it is re-expanded. It still feels like I've overlooked something or I'm not using the provided tools effectively, but its sufficient for me to get by for now and I'm under a deadline. Would it be possible to add some kind of check to raise an error and prevent PyQt from segfaulting with the original script? Darren
""" """ from PyQt4 import QtCore, QtGui from functools import wraps import time class TreeItem(object): def __init__(self, data, parent=None): self._parent = parent self._data = data self._children = [] @property def children(self): return self._children @property def columns(self): return [self.data['id'], self.data['description']] @property def data(self): return self._data @property def hasChildren(self): return False @property def parent(self): return self._parent @property def row(self): if self.parent: return self.parent.children.index(self) return 0 def clearChildren(self): self._children = [] def __len__(self): return len(self.children) class RootItem(TreeItem): def __init__(self): self._parent = None self._children = [] @property def children(self): return self._children @property def columns(self): return ['ID', 'Description'] @property def hasChildren(self): return True def appendChild(self, child): self._children.append(child) class DictItem(TreeItem): def __init__(self, data, parent=None): super(DictItem, self).__init__(data, parent) @property def children(self): if not self._children: self._children = [TreeItem(child, self) for child in self.data['children']] return self._children @property def hasChildren(self): return True class FileModel(QtCore.QAbstractItemModel): """ """ def __init__(self, parent=None): super(FileModel, self).__init__(parent) self._rootItem = RootItem() @property def rootItem(self): return self._rootItem def canFetchMore(self, index): parentItem = index.internalPointer() if parentItem is not None: return len(parentItem) == 0 else: return False def columnCount(self, parent): if parent.isValid(): return len(parent.internalPointer().columns) else: return len(self.rootItem.columns) def data(self, index, role): if not index.isValid() or role != QtCore.Qt.DisplayRole: return QtCore.QVariant() item = index.internalPointer() return QtCore.QVariant(item.columns[index.column()]) def fetchMore(self, index): parentItem = index.internalPointer() if parentItem is not None: self.beginInsertRows(index, 0, len(parentItem)) parentItem.children self.endInsertRows() def hasChildren(self, index): parentItem = index.internalPointer() if parentItem is not None: return parentItem.hasChildren else: return True def headerData(self, section, orientation, role): if orientation == QtCore.Qt.Horizontal and \ role == QtCore.Qt.DisplayRole: return QtCore.QVariant(self.rootItem.columns[section]) return QtCore.QVariant() def index(self, row, column, parent): if not self.hasIndex(row, column, parent): return QtCore.QModelIndex() if parent.isValid(): parentItem = parent.internalPointer() else: parentItem = self.rootItem child = parentItem.children[row] return self.createIndex(row, column, child) def parent(self, index): if not index.isValid(): return QtCore.QModelIndex() parent = index.internalPointer().parent if parent == self.rootItem or parent is None: return QtCore.QModelIndex() return self.createIndex(parent.row, 0, parent) def clearRows(self, index): parent = index.internalPointer() self.beginRemoveRows(index, 0, len(parent)) parent.clearChildren() self.endRemoveRows() self.appendAnother() def rowCount(self, parent): if parent.isValid(): parentItem = parent.internalPointer() else: parentItem = self.rootItem return len(parentItem) def appendDict(self, d): assert 'id' in d assert 'description' in d self.rootItem.appendChild(DictItem(d)) def appendAnother(self): self.rootItem.children[0].data['children'].append({'id':3, 'description':'child 3'}) class FileView(QtGui.QTreeView): def __init__(self, model=None, parent=None): super(FileView, self).__init__(parent) self.setModel(model) self.connect(self, QtCore.SIGNAL('collapsed(QModelIndex)'), model.clearRows) if __name__ == '__main__': import sys app = QtGui.QApplication(sys.argv) c1 = {'id':1, 'description':'child 1'} c2 = {'id':2, 'description':'child 2'} d = {'id':0, 'description':'whatever', 'children':[c1, c2]} model = FileModel() form = FileView(model) model.appendDict(d) form.show() sys.exit(app.exec_())
_______________________________________________ PyQt mailing list PyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt