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

Reply via email to