Dear all, I am trying to use a Python list as a model for QTreeView, or to be precise, the model is a subclass of list, the daughter nodes are the elements on this list object, and they themselves are the same subclass of list.
Somehow I cannot get the data to show correctly. Only the first row is shown and although the top row indicates that is has subrows, expanding the toprow does not show the subrows. I adapted the sample program that comes with the PyQt source distribution to illustrate the problem. Uncomment the code at line 194/195 to select the working code or my failing code. I observe this problem when I run this on a Mac Book Pro (Mac OS X 10.6.4, Python 2.6, Qt 4.6.3, PyQt 4.7.4). I haven't had the opportunity to test this on other platforms. I'm not sure if there is some mistake in my code or this is a bug in PyQt or Qt. Iv'e found one reference on the web to what sounds like a similar problem: http://www.python-forum.org/pythonforum/viewtopic.php?f=4&t=14676. Could anyone offer any insights? Many thanks in advance. Best, Herbert
#!/usr/bin/env python ############################################################################ ## ## Copyright (C) 2005-2005 Trolltech AS. All rights reserved. ## ## This file is part of the example classes of the Qt Toolkit. ## ## This file may be used under the terms of the GNU General Public ## License version 2.0 as published by the Free Software Foundation ## and appearing in the file LICENSE.GPL included in the packaging of ## this file. Please review the following information to ensure GNU ## General Public Licensing requirements will be met: ## http://www.trolltech.com/products/qt/opensource.html ## ## If you are unsure which license is appropriate for your use, please ## review the following information: ## http://www.trolltech.com/products/qt/licensing.html or contact the ## sales department at sa...@trolltech.com. ## ## This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ## WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ## ############################################################################ # Modified to illustrate that QTreeView does not handle a model that is # subclassed from a Python list. from PyQt4 import QtCore, QtGui # set dbg = True on the line below to see that only the first row is ever # requested, altough rowCount() returns 2. dbg = False # Everything works when creating a new class for the model class TreeItem_Works(object): def __init__(self, data): self.parentItem = None self.itemData = data self.dtrs = [] def appendChild(self, item): item.parentItem = self self.dtrs.append(item) def child(self, row): return self.dtrs[row] def childCount(self): return len(self.dtrs) def columnCount(self): return len(self.itemData) def get_data(self, column): try: return self.itemData[column] except IndexError: return None def parent(self): return self.parentItem def row(self): if self.parentItem: return self.parentItem.dtrs.index(self) return 0 def __str__( self ) : return self.to_string( indent = 0 ) def to_string( self, indent = 0 ) : string = ' ' * indent + repr( self.itemData ) + '\n' d_indent = indent + 2 for index in range( 0, self.childCount() ) : dtr = self.child( index ) string += dtr.to_string( d_indent ) return string # Only the first row is shown (but not its daughters) when using this class # that equates the list of daughters with the TreeItem itself by subclassing # from list. (Btw. subclassing from UserList.UserList has the same result.) #import UserList #class TreeItem_Fails(TreeItem_Works, UserList.UserList): # def __init__(self, data): # UserList.UserList.__init__( self ) # self.parentItem = None # self.itemData = data class TreeItem_Fails(TreeItem_Works, list): def __init__(self, data): list.__init__( self ) self.parentItem = None self.itemData = data def appendChild(self, item): item.parentItem = self self.append(item) def child(self, row): return self[row] def childCount(self): return len(self) def row(self): if self.parentItem: return self.parentItem.index(self) return 0 class TreeModel(QtCore.QAbstractItemModel): def __init__(self, root_item, parent=None): QtCore.QAbstractItemModel.__init__(self, parent) self.rootItem = root_item def columnCount(self, parent): if parent.isValid(): source = parent.internalPointer() else: source = self.rootItem if dbg : print "%s columns for %s" % ( source.columnCount(), source.itemData ) return source.columnCount() def rowCount(self, parent): if parent.column() > 0: return 0 if not parent.isValid(): parentItem = self.rootItem else: parentItem = parent.internalPointer() if dbg : print "%s rows for %s" % ( parentItem.childCount(), parentItem.itemData ) return parentItem.childCount() def index(self, row, column, parent): if not self.hasIndex(row, column, parent): return QtCore.QModelIndex() if not parent.isValid(): parentItem = self.rootItem else: parentItem = parent.internalPointer() childItem = parentItem.child(row) if childItem: if dbg : print "%s at %s,%s is %s" % ( parentItem.itemData, row, column, childItem.itemData ) return self.createIndex(row, column, childItem) else: return QtCore.QModelIndex() def parent(self, index): if not index.isValid(): return QtCore.QModelIndex() childItem = index.internalPointer() parentItem = childItem.parent() if parentItem == self.rootItem: return QtCore.QModelIndex() if dbg : print "%s at %s,%s has parent %s at %s,%s" % ( childItem.itemData, index.row(), index.column(), parentItem.itemData, parentItem.row(), 0 ) return self.createIndex(parentItem.row(), 0, parentItem) def data(self, index, role): if not index.isValid(): return None if role != QtCore.Qt.DisplayRole: return None item = index.internalPointer() if dbg : print "%s at %s,%s is %s" % (item.itemData, index.row(), index.column(), item.get_data(index.column()) ) return item.get_data(index.column()) def flags(self, index): if not index.isValid(): return QtCore.Qt.NoItemFlags return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable def headerData(self, section, orientation, role): if orientation == QtCore.Qt.Horizontal and role == \ QtCore.Qt.DisplayRole: return self.rootItem.get_data(section) return None if __name__ == '__main__': import sys # Select TreeItem_Works for a working example. # Select TreeItem_Fails to show that subclassing from list shows only # the first row TreeItem = TreeItem_Works #TreeItem = TreeItem_Fails node = TreeItem( ( '1', 'i' ) ) node.appendChild( TreeItem( ( 'A', 'a' ) ) ) leaf = TreeItem( ( 'B', 'b' ) ) root_item = TreeItem(("Title", "Summary")) root_item.appendChild( node ) root_item.appendChild( leaf ) print root_item app = QtGui.QApplication(sys.argv) model = TreeModel( root_item ) view = QtGui.QTreeView() view.setModel(model) view.setWindowTitle("Simple Tree Model") view.show() sys.exit(app.exec_())
_______________________________________________ PyQt mailing list PyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt