Thursday, January 29, 2015

PySide Tree Tutorial IID: Adding helper methods to TreeItem

Part of a series on treebuilding in PySide: see Table of Contents.   

In part IIB we saw how to build a tree structure out of TreeItem instances. What we didn't discuss there is that each TreeItem comes packed with additional methods that will help us construct our tree model. Most of these methods let us extract simple data from a TreeItem, such as its parent, or the text from one of its columns. In this post, we'll go over these methods.

Via the child() method, an item returns one of its children from the given row:

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

Recall from Figure 2 (post IB) that in tree models, children are arranged as a set of rows underneath their parents. Hence, to pick child n from a parent, just select the nth member from the parent's childItems list.

The number of children an item has is calculated in childCount():

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

This just returns the length of the list that contains all the children.

The row() method reports an item's position among its siblings. For example, in Figure 5 (post IIB), the item marked A occupies row 0 among its siblings, while item D has the same parent, and occupies row 1. Item C is a child of A, and occupies row 1 among A's children.  

row() is implemented as follows:

def row(self):
    if self.parentItem:
        return self.parentItem.childItems.index(self) 
    return 0 

We should note a couple of things about row(). First, index() in this case has nothing to do with the model indexes mentioned in post IB: it is simply the built-in Python method that returns the index at which a given value occurs in a list. Second, our convention is that the root item is automatically assigned to row 0, even though it has no parent (Figure 5).

The number of columns of data associated with an item is returned by columnCount():

def columnCount(self):
    return len(self.itemData) 

Each item in our data structure contains the same number of columns, so we could have simply returned 2, but we have opted for a more general approach.

The data() method lets you extract the textual data from a particular column in a row (recall Figure 4, post IIB). It simply retrieves the text from the appropriate column stored in itemData:

def data(self, column):
        return self.itemData[column]
    except IndexError:
        return None

Note that data() returns None if the column index is out of range.

An item's parent is returned, surprisingly enough, from parent():

def parent(self):
    return self.parentItem

This will return None for the root node.

There you have it: we have built a beautiful tree of data, along with some methods that the model will use to extract different features of its nodes. What is interesting is that, up until now, we have officially done zero PySide programming. We have done all our work with standard Python classes, without importing QtGui, QtCore, or any other PySide classes. In the next section we will finally do some PySide programming, and look at how to wrap a model around this tree.

No comments: