I suggest you just attach the files that contain this code instead of pasting them here inline.<div><br><br><div class="gmail_quote">On Sun, Oct 10, 2010 at 11:27, Knacktus <span dir="ltr"><<a href="mailto:knacktus@googlemail.com">knacktus@googlemail.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">OK, here the last update, I promise ;-) ...<br>
(The expand_below action was broken - not sensitive for the problem, but for correctnes of the code):<br>
<br>
<br>
<br>
import sys<br>
import PyQt4.QtGui as QtGui<br>
import PyQt4.QtCore as QtCore<br>
<br>
<br>
#########################################################################<br>
# Underlying data<br>
# ----------------<br>
# - RuntimeItems hold the data. They come from a database.<br>
# - ViewItems are the objects, that are given to the model indexes of Qt.<br>
#   They are constructed according to some rules like filters and<br>
#   configuration.<br>
# - DummieViewItemFactory processes the rules and configurations.<br>
#   The example here is simplfied. An instance of the factory is given<br>
#   to each ViewItem.<br>
#   The view item calls the<br>
#   DummieViewItemFactory.get_view_item_children method<br>
#   to request calculation of its children on demand.<br>
# - For this demo-version, the number of items is controlled by<br>
#   DummieViewItemFactory.max_items. It's passed in by the constructor.<br>
# - Nesting as high as possible: One child per parent.<br>
#########################################################################<br>
<br>
<br>
class RuntimeItem(object):<br>
    """Represent the real world business items. These objects<br>
    have a lot of relations.<br>
    """<br>
<br>
    def __init__(self, name, ident, item_type):<br>
        <a href="http://self.name" target="_blank">self.name</a> = name<br>
        self.ident = ident<br>
        self.item_type = item_type<br>
<br>
<br>
class ViewItem(object):<br>
    """Represent items that are to be shown to the user in a QTreeView.<br>
    Those items do only occur one time in a view. They have a<br>
    corresponding runtime_item.<br>
    The children are calculated by the view_item_factory on demand.<br>
    """<br>
<br>
    def __init__(self, view_item_factory, runtime_item=None, parent=None,<br>
                 hidden_runtime_items=None):<br>
        self.view_item_factory = view_item_factory<br>
        self.runtime_item = runtime_item<br>
        self.parent = parent<br>
        self.hidden_runtime_items = hidden_runtime_items<br>
<br>
    @property<br>
    def children(self):<br>
        try:<br>
            return self._children<br>
        except AttributeError:<br>
            self._children = \<br>
                self.view_item_factory.get_view_item_children(self)<br>
            return self._children<br>
<br>
    @children.setter<br>
    def children(self, children):<br>
        self._children = children<br>
<br>
<br>
class DummieViewItemFactory(object):<br>
    """Creates the view_items. This is a dumb dummie as a simple<br>
    example. Normally a lot of things happen here like filtering<br>
    and configuration. But once the view_item hierachy is build,<br>
    this shouldn't be called at all.<br>
    """<br>
<br>
    def __init__(self, runtime_item, max_items):<br>
        self.runtime_item = runtime_item<br>
        self.max_items = max_items<br>
        self.item_counter = 0<br>
        self.aux_root_view_item = ViewItem(self)<br>
<br>
    def get_view_item_children(self, view_item_parent):<br>
        if self.item_counter > self.max_items:<br>
            return []<br>
        self.item_counter += 1<br>
        view_item = ViewItem(self, self.runtime_item, view_item_parent)<br>
        return [view_item]<br>
<br>
<br>
#########################################################################<br>
# Qt classes<br>
# ----------------<br>
# - This should be standard stuff. I've got most of it from the Rapid<br>
#   GUI Programming book.<br>
# - The ActiveColums class tells the model which colums to use.<br>
# - The TreeView has a context menu with navigation actions.<br>
# - The expand_all calls the Qt slot. Here the surprise for the<br>
#   performance.<br>
#########################################################################<br>
<br>
<br>
class ActiveColumns(object):<br>
<br>
    def __init__(self, columns):<br>
        self.columns = columns<br>
<br>
<br>
class TreeView(QtGui.QTreeView):<br>
<br>
    def __init__(self, aux_root_view_item, active_columns, parent=None,<br>
                 header_hidden=False):<br>
        super(TreeView, self).__init__(parent)<br>
        self.setIndentation(10)<br>
        self.active_columns = active_columns<br>
        self.setAlternatingRowColors(True)<br>
        self.setHeaderHidden(header_hidden)<br>
        self.setAllColumnsShowFocus(True)<br>
        self.setUniformRowHeights(True)<br>
        self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)<br>
<br>
        self.model = TreeModel(aux_root_view_item, self)<br>
        self.setModel(self.model)<br>
<br>
        e_a_action = QtGui.QAction("Expand all", self)<br>
        e_a_action.setToolTip("Expands all items of the tree.")<br>
        e_a_action.triggered.connect(self.expand_all)<br>
<br>
        e_a_b_action = QtGui.QAction("Expand all below", self)<br>
        e_a_b_action.setToolTip("Expands all items under the selection.")<br>
        e_a_b_action.triggered.connect(self.expand_all_below)<br>
<br>
        c_a_action = QtGui.QAction("Collapse all", self)<br>
        c_a_action.setToolTip("Collapses all items of the tree.")<br>
        c_a_action.triggered.connect(self.collapse_all)<br>
<br>
        c_a_b_action = QtGui.QAction("Collapse all below", self)<br>
        c_a_b_action.setToolTip("Collapses all items under the selection.")<br>
        c_a_b_action.triggered.connect(self.collapse_all_below)<br>
<br>
        for action in (e_a_action, c_a_action, e_a_b_action, c_a_b_action):<br>
            self.addAction(action)<br>
<br>
    def expand_all(self):<br>
        self.expandAll()<br>
<br>
    def collapse_all(self):<br>
        self.collapseAll()<br>
<br>
    def expand_all_below(self):<br>
        def expand_all_below_recursive(parent_index):<br>
            self.expand(parent_index)<br>
            children_indexes = \<br>
                self.model.get_children_indexes(parent_index)<br>
            for child_index in children_indexes:<br>
                expand_all_below_recursive(child_index)<br>
<br>
        indexes = self.selectedIndexes()<br>
        if indexes:<br>
            index = indexes[0]<br>
            expand_all_below_recursive(index)<br>
<br>
    def collapse_all_below(self):<br>
        def collapse_all_below_recursive(parent_index):<br>
            self.collapse(parent_index)<br>
            children_indexes = \<br>
                self.model.get_children_indexes(parent_index)<br>
            for child_index in children_indexes:<br>
                collapse_all_below_recursive(child_index)<br>
<br>
        indexes = self.selectedIndexes()<br>
        if indexes:<br>
            index = indexes[0]<br>
            collapse_all_below_recursive(index)<br>
<br>
class TreeModel(QtCore.QAbstractItemModel):<br>
<br>
    def __init__(self, aux_root_view_item, parent):<br>
        super(TreeModel, self).__init__(parent)<br>
        self.aux_root_view_item = aux_root_view_item<br>
        self.active_columns = parent.active_columns<br>
<br>
    def rowCount(self, parent_index):<br>
        parent_view_item = self.view_item_from_index(parent_index)<br>
        if parent_view_item is None:<br>
            return 0<br>
        return len(parent_view_item.children)<br>
<br>
    def get_children_indexes(self, parent_index):<br>
        children_indexes = []<br>
        for row_no in range(self.rowCount(parent_index)):<br>
            children_indexes.append(self.index(row_no, 0, parent_index))<br>
        return children_indexes<br>
<br>
    def columnCount(self, parent):<br>
        return len(self.active_columns.columns)<br>
<br>
    def data(self, index, role):<br>
        if role == QtCore.Qt.TextAlignmentRole:<br>
            return int(QtCore.Qt.AlignTop|QtCore.Qt.AlignLeft)<br>
        if role != QtCore.Qt.DisplayRole:<br>
            return None<br>
        view_item = self.view_item_from_index(index)<br>
        try:<br>
            data = getattr(view_item.runtime_item,<br>
                           self.active_columns.columns[index.column()])<br>
        except AttributeError:<br>
            data = ""<br>
        return data<br>
<br>
    def headerData(self, section, orientation, role):<br>
        if (orientation == QtCore.Qt.Horizontal and<br>
            role == QtCore.Qt.DisplayRole):<br>
            assert 0 <= section <= len(self.active_columns.columns)<br>
            return self.active_columns.columns[section]<br>
        return QtCore.QVariant()<br>
<br>
    def index(self, row, column, parent_index):<br>
        view_item_parent = self.view_item_from_index(parent_index)<br>
        return self.createIndex(row, column,<br>
                                view_item_parent.children[row])<br>
<br>
    def parent(self, child_index):<br>
        child_view_item = self.view_item_from_index(child_index)<br>
        if child_view_item is None:<br>
            return QtCore.QModelIndex()<br>
        parent_view_item = child_view_item.parent<br>
        if parent_view_item is None:<br>
            return QtCore.QModelIndex()<br>
        grandparent_view_item = parent_view_item.parent<br>
        if grandparent_view_item is None:<br>
            return QtCore.QModelIndex()<br>
        grandparent_view_item<br>
        row = grandparent_view_item.children.index(parent_view_item)<br>
        assert row != -1<br>
        return self.createIndex(row, 0, parent_view_item)<br>
<br>
    def view_item_from_index(self, index):<br>
        return (index.internalPointer()<br>
                if index.isValid() else self.aux_root_view_item)<br>
<br>
<br>
if __name__ == "__main__":<br>
<br>
    run_time_item = RuntimeItem("Test", "test_12", "Test Item")<br>
    view_factory = DummieViewItemFactory(run_time_item, max_items=5000)<br>
    active_colums = ActiveColumns(["name", "ident", "item_type"])<br>
<br>
    app = QtGui.QApplication(sys.argv)<br>
    tree_view = TreeView(view_factory.aux_root_view_item, active_colums)<br>
    app.setApplicationName("IPDM")<br>
    tree_view.show()<br>
    app.exec_()<br>
<br>
<br>
<br>
<br>
<br>
_______________________________________________<br>
PyQt mailing list    <a href="mailto:PyQt@riverbankcomputing.com" target="_blank">PyQt@riverbankcomputing.com</a><br>
<a href="http://www.riverbankcomputing.com/mailman/listinfo/pyqt" target="_blank">http://www.riverbankcomputing.com/mailman/listinfo/pyqt</a><br>
</blockquote></div><br><br clear="all"><br>-- <br>Nick Gaens<br>
</div>