[PyQt] Model/View programming

David Boddie dboddie at trolltech.com
Thu Sep 24 20:11:34 BST 2009


On Tue Sep 22 01:37:33 BST 2009, David Boddie wrote:

> I tried running your test case and found that the view displayed various
> items in an incomplete way - when you see trailing branches, it's a sure
> sign that something isn't quite right.
>
> I'll try and take a look at this tomorrow unless someone manages to help
> you out in the meantime.

I finally got a chance to look at the code. I removed all the places where
you stored QModelIndexes in the items and changed the appendChild() method
to emit signals so that the view knows something changed.

You might want to diff my version against yours to see what I did.

David
-------------- next part --------------
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class GeneralItem(object):
    def __init__(self,  name = str(),  parent = None,  size = int(),  time = QDateTime(),  permission = str()):
        
        self.setName(name)
        self.setParent(parent)
        self.setSize(size)
        self.setTime(time)
        self.setPermission(permission)
    
    def setName(self,  name):
        self.__name = name
    
    def setParent(self,  parent):
        self.__parent = parent
    
    def setSize(self,  size):
        self.__size = size
    
    def setTime(self,  time):
        self.__time = time
    
    def setPermission(self,  permission):
        self.__permission = permission
    
    def name(self):
        return self.__name
    
    def parent(self):
        return self.__parent
    
    def row(self):
        if self.parent():
            return self.parent().children().index(self)
        return 0
    
    def size(self):
        return self.__size
    
    def time(self):
        return self.__time
    
    def permission(self):
        return self.__permission

class DirectoryItem(GeneralItem):
    def __init__(self,  name = str(),  parent = None,  size = int(),  time = QDateTime(),  permission = str()):
        GeneralItem.__init__(self,  name,  parent,  size,  time,  permission)
        
        self.clearChildren()

    def children(self):
        return self.__children
    
    def hasChildren(self):
        return bool(self.children())

    def appendChild(self,  child):
        child.setParent(self)
        self.__children.append(child)

    def clearChildren(self):
        self.__children = list()

    def __len__(self):
        return len(self.children())

def FileItem(GeneralItem):
    def hasChildren(self):
        return False

class ObexDirectoryView(QAbstractItemModel):
    def __init__(self):
        QAbstractItemModel.__init__(self)

        self.__rootItem = DirectoryItem()

    def rowCount(self,  parent=QModelIndex()):
        if parent.isValid():
            parentItem = parent.internalPointer()
        else:
            parentItem = self.__rootItem
        return len(parentItem)

    def hasChildren(self,  index=QModelIndex()):
        parentItem = index.internalPointer()
        if parentItem is not None:
            return parentItem.hasChildren()
        else:
            return True

    def columnCount(self,  parent=QModelIndex()):
        return 1

    def index(self, row, column, parent=QModelIndex()):
        if not self.hasIndex(row, column, parent):
            return QModelIndex()

        if parent.isValid():
            parentItem = parent.internalPointer()
        else:
            parentItem = self.__rootItem

        child = parentItem.children()[row]
        index = self.createIndex(row, column, child)
        return index

    def parent(self, index):
        if not index.isValid():
            return QModelIndex()

        parent = index.internalPointer().parent()
        if parent == self.__rootItem or parent is None:
            return QModelIndex()
        
        return self.createIndex(parent.row(), 0, parent)

    def data(self,  index,  role = Qt.DisplayRole):
        if index.isValid() and role == Qt.DisplayRole and index.column() == 0:
            item = index.internalPointer()
            return QVariant(item.name())
        
        return QVariant()

    def appendChild(self,  child,  parent=None):
        if parent == None:
            parent = self.__rootItem
        
        if parent == self.__rootItem:
            parentIndex = QModelIndex()
        else:
            parentIndex = self.createIndex(parent.row(), 0, parent)
        
        row = len(parent)
        self.beginInsertRows(parentIndex, row, row)
        parent.appendChild(child)
        self.endInsertRows()
        index = self.createIndex(row, 0, child)
        self.dataChanged.emit(index, index)

class ColumnView(QTreeView):
    def __init__(self):
        super(ColumnView,  self).__init__()

        self.model = ObexDirectoryView()
        
        item1 = DirectoryItem("Root Item 1")
        item2 = DirectoryItem("Root Item 2")
        item3 = DirectoryItem("Child 1 of Root 1")
        item4 = DirectoryItem("Child 1 of Root 2")
        
        self.model.appendChild(item1)
        self.model.appendChild(item2)
        self.model.appendChild(item3,  item1)
        self.model.appendChild(item4,  item2)
        
        self.setModel(self.model)
        

        self.resize(700,  700)
        self.show()
        
        item5 = DirectoryItem("Root Item 3")
        item6 = DirectoryItem("Child 1 of Root 3")
        
        self.model.appendChild(item5)
        self.model.appendChild(item6,  item5)
        

app = QApplication([])
m = ColumnView()
app.exec_()


More information about the PyQt mailing list