Implementing an empty root item for QAbstractItemModel

294 views
Skip to first unread message

Bay

unread,
Oct 29, 2013, 3:28:29 AM10/29/13
to python_in...@googlegroups.com
Hi, 
    A problem I've been having with implementing my model is that I needed to declare a root item initially so my model would be able to initialize with a valid parent. I implemented it like so : 

class SceneGraphModel(QtCore.QAbstractItemModel):

        def __init__(self, parent=None):
            super(SceneGraphModel, self).__init__(parent)
            self._rootNode=Node(None)
            self.nodeRole = QtCore.Qt.UserRole


        def rowCount(self, parent):
            if not parent.isValid():
                parentNode=self._rootNode
            else:
                parentNode = parent.internalPointer()

As you can see I created an empty Node Class object under the variable self._rootNode. Now I had no issues with being able to insert rows and remove them. However, it seems that declaring it initially as None is causing it to clash with my rowCount() method in my model class , first with the isValid() method and if I remove that. I will get a :

AttributeError: 'NoneType' object has no attribute 'childCount'

I'm assuming from this error that declaring it as None initially means it doesn't have any attributes which the model class seems to have problems dealing with. And even after inserting some rows it still has no valid childCount to access. Below is my Node class:

class Node(object):

    def __init__(self, fullname, parent=None):

        self._fullName=fullname
        self._children=[]
        self._parent=parent


        if parent is not None:
            parent.addChild(self)


    def addChild(self, child):
        self._children.append(child)

    def insertChild(self, position, child):

        if position < 0 or position > len(self._children):
            return False

        self._children.insert(position, child)
        child._parent = self
        return True

    def removeChild(self, position):

        if position < 0 or position > len(self._children):
            return False

        child = self._children.pop(position)
        child._parent = None

        return True

    def name(self):
        return self._name

    def setName(self,name):
        self._name=name

    def child(self, row):
            return self._children[row]

    def childCount(self):
            return len(self._children)

    def parent(self):
        return self._parent

    def row(self):
        if self._parent is not None:
            return self._parent._children.index(self)

Is there a way of implementing this root node? So far the examples I've managed to find all seems to initialize the model with information already inserted and do not start off with an empty model. Is this supposed to be a design limitation of PyQT or am I just doing this wrong? 

Thank you
Gann Boon Bay

Jesse Kretschmer

unread,
Oct 30, 2013, 5:25:15 PM10/30/13
to python_in...@googlegroups.com
On Tue, Oct 29, 2013 at 12:28 AM, Bay <gannbo...@gmail.com> wrote:
AttributeError: 'NoneType' object has no attribute 'childCount'

Can you show the code that is calling childCount()?

In Node.row() there is a check to see that self._parent is not None before attempting to execute any operations for self._parent. From SceneGraphModel.rowCount(), parent is provided as an argument. The code that calls rowCount should make sure parent is valid, or that validation can be added to the rowCount() directly.

Without having a more complete view of what you are working on it's hard to provide much more input in regards to this specific error.

There are plenty of ways to handle the validation. For example, you can test type() or hasattr() before executing code that expects the special methods or attributes to be available.

Bay

unread,
Oct 31, 2013, 2:08:00 AM10/31/13
to python_in...@googlegroups.com

Hi Jesse, 
              thanks for taking the time and effort to reply to me. After weeks of trying to wracking my head and pretty much filling this board with my pleas for help I think realized my problem. 
  
              All along I've thought that the Node class was meant only as a helper class for the Model to condense its commands so I kept trying to get information about my node via the model class functions which I probably couldn't get anyway since the information of the Nodes instances created are already accessible through their own class methods. It's just that I got my logic about retrieving the information I wanted turned around, that's why I couldn't get my commands to work and didn't understand the errors. 

            I was trying to get the children of the main root through the rowCount method so I can compare it with new row entries to see if there were a duplicate and kept trying to accomplish that via this method in my QAbstractItemView

            def rowCount(self, parent):

            if not parent.isValid():
                parentNode=self._rootNode
            else:
                parentNode = parent.internalPointer()


            return parentNode.childCount()

When I could have simply just get it like this - self._model._rootNode.childList(). The childList method in my node class being like this     
            def childList(self):
                  for child in range(len(self._children)):
                        print self._children[child].fullName()

It's a very silly mistake to have made and I can't imagine why I had thought it was so complex. I hope my describing my amateur problem here would help any new comers to PyQt. 
Reply all
Reply to author
Forward
0 new messages