Listbox and listview iterators

Often, you find yourself iterating over all items in a QListBox (or you own subclass) to get selected items only. Using a generator (Python 2.2 +), this gets very intuitive:

def ListBoxIterator(listbox):
    i = listbox.firstItem()
    while i:
        yield i
        i = i.next()

If you then want to get selected items only, you can do this very pythonic(tm) by using ifilter(...) from the itertools module (Python 2.3+)

ifilter(lambda x: x.isSelected(), 
        ListBoxIterator(listbox))

It is also possible to use this in a list comprehension, which returns a list immediately and not another iterator:

selected_items = [i for i in ListBoxIterator(listbox) if i.isSelected()]

Another possibility is installing this function as a method of the QListBox class, enabling its use as a iterable object:

QListBox.__iter__ = ListBoxIterator

...

for item in listbox:
    print item

For a QListView, there are two different iterators, one that only walks over first-level children:

def FlatLVIterator(parent):
    child = parent.firstChild()
    while child:
        yield child
        child = child.nextSibling()

The other one traverses the whole tree below a node:

def DeepLVIterator(parent):
    child = parent.firstChild()
    while child:
        yield child
        for c in DeepLVIterator(child):
            yield c
        child = child.nextSibling()

Note, that you can supply both instances of QListView and QListViewItem to this generators, which would not be possible in C++, because they do not have a common base class interface. In Python, everything is method- (or message-, if you prefer Smalltalk) based, and both classes have a firstChild() member.

The searching functions in QListView are very limited. This generator delivers all matches for a given string or QRegExp:

def SearchLVIterator(parent, searchPattern):
    for item in DeepLVIterator(parent):
        txt = item.text(0)
        if txt.contains(searchPattern):
            yield item

This is only a shortcut, because it could also be done with ifilter(...) or a list comprehension.

ListBoxAndListViewIterators (last edited 2005-04-09 13:04:20 by )