I've been stumbled a bit just now, trying to populate an NSOutlineView from PyObjC.

When I was starting, I tried to do everything with Cocoa Bindings. Alas, it was too complicated for my small brain (although I was happily binding my NSTableView with very little fuss), so I went and created my own datasource.

Using Python, it's very simple. All you need class that implements the following:

def outlineView_numberOfChildrenOfItem_(self, outlineView, item):
def outlineView_isItemExpandable_(self, outlineView, item):
def outlineView_child_ofItem_(self, outlineView, index, item):
def outlineView_objectValueForTableColumn_byItem_(self, outlineView, tableColumn, item):

You have to always keep in mind that if item is None then it means it's your root item, and you should act accordingly: I wanted to create an Finder-like source view, so I actually had a table of plain strings (eg. PLACES, SHARED and so on).

Everything was working fine: After some false starts, I could get my labels to appear, but as soon as everything was up, I got dumped in the debugger with no information.

Tip: bt FTW

Typing bt in the XCode debugger will give you the backtrace of the offending call. In my case, it wasn't helpful (something about pythonifying). Trying continue I got: Received BAD_ACCESS (or something like that).

Diving a bit into the PyObjC examples (as I should've done earlier), I've noticed that you can't pass python objects in an NSOutlineView, because it doesn't retain it's values, so everything goes away and the next time round in the message loop there is no reference to my strings.

So the solution is to wrap everything in an NSString:

def NSStringify(l):
    return map(lambda s: NSString.alloc().initWithString_(s), l)

ROOTS = NSStringify(["AUTHORS", 'TAGS'])

Final Implementation

FWIW, my data source looks like this:

def outlineView_numberOfChildrenOfItem_(self, outlineView, item):
    if item is None:
        return len(ROOTS)
    if item == "TAGS":
        return len(self.tags)
    if item == "AUTHORS":
        return len(self.authors)
    return 0

def outlineView_isItemExpandable_(self, outlineView, item):
    if item in ROOTS:
        return True
    return False

def outlineView_child_ofItem_(self, outlineView, index, item):
    if item is None:
        return ROOTS[index]
    if item == 'AUTHORS':
        return self.authors[index]
    if item == 'TAGS':
        return self.tags[index]
    return None

def outlineView_objectValueForTableColumn_byItem_(self, outlineView, tableColumn, item):
    if isinstance(item, NSManagedObject):
        if item.entity().name() in ['Tag', 'Author']:
            return item.Name()
    return str(item)

(as you can tell, self.authors and self.tags are CoreData collections - more on that in another post).

Perhaps this post will help someone who is struggling with PyObjC.

June 7, 2008, 9:16 p.m. More (387 words) 1 comment Feed
Previous entry: Explosion: Aftermath
Next entry: iPhone, MobileMe and 3rd party applications

Comments

1

Comment by John Velman , 3 years, 10 months ago :

I'm trying to develop a (relatively simple) database view, edit, print and save application. I need to develop on Leopard, it needs to run on Tiger. I initially thought Python, PyQt, SQLite. I'm new to Mac, not real proficient with Python (but comfortable with it and think I know where to look for answers).

On the python-mac SIG I got two other suggestions -- Dabo, and developing in Cocoa directly using PyObjC. (Both Dabo and QT have problems from my point of view.) I really like the concept of PyObjC, and am trying to go forward with this. But lots of lack of documentation and examples for XCode 3!

Anyway, thanks for your information, and thanks to others for contributions to this blog.

I'll be following it.

Best!


This post is older than 30 days and comments have been turned off.