views:

313

answers:

2

How would you Subclass an NSOutlineView?

+3  A: 

@interface MyOutlineView : NSOutlineView { ... } ... @end

Noah Witherspoon
Oh I see, What would I put where the dots are?
Joshua
Oh i put my code there. Would I need to put anything in the header file?
Joshua
That is what goes in the header file; the first `...` is for instance variables, the second for method signatures. The .m contains the `@implementation MyOutlineView...@end`with your actual method... implementations.
Noah Witherspoon
I see, would this class file have to be the Outline View's data source?
Joshua
+12  A: 

Firstly, before you subclass an object, you should ask yourself "do I need to do this?". Subclassing is a more complex way of interacting and extending the functionality of other classes, so you should make sure that what you are trying to achieve cannot easily be achieved through another, simpler method, such as delegation, notifications etc. Obviously if you are trying to change the way the control looks this is going to be more easily accomplished through subclassing, but make sure you check all the other available options. Remember that NSOutlineView has a fairly long object tree - it inherits from NSTableView, which inherits from NSControl, which inherits from NSView, which inherits from NSResponder which inherits from NSObject, and there are various helper methods that exist in each of these classes which can often help you achieve what you want.

However, if you check all of these options and decide to subclass NSOutlineView, it depends what you want to do with your subclass. The easiest way to create the shell of your subclass would be to select File > New File then choosing Objective-C class, as you would with any other class, which will create a new class, with header and implementation files, that inherits from NSObject. Then you can simply change the line in your header file:

@interface MyClass : NSObject { // Where MyClass is the name of your class

to

@interface MyClass : NSOutlineView {

which will cause your class to inherit from NSOutlineView. Since it is a subclass of NSOutlineView, this gives you lots of opportunities to change the default behaviour of the control.

Since you are creating a subclass, you can change the default implementation of any method up the object tree - that is, you can override methods declared in NSOutlineView, NSTableView, NSControl, NSView, NSResponder and NSObject (although you should rarely override methods declared in NSObject). You do not need to redefine the method signature in your header file, you can simply override the function by implementing it in your subclass's implementation. For example, if you wanted to override NSView's drawRect: method, you would do the following in your subclass's implementation:

- (void)drawRect:(NSRect)rect //Method signature from the docs
{
    //Code here
}

When drawRect: is called upon your class, your code will be executed instead of the code in NSView.

You can also pass method calls up the tree for methods that you do not want to handle. This is done by default, so you do not need to create empty methods that simply call the method on super, however, if you override a method and want to allow one of your superclasses to handle it first, you could do the following:

- (void)expandItem:(id)item
{
    [super expandItem:item];

    //Your code here
}

This would be beneficial if you wanted to change a variable in your class, for example, but provide the default implementation of the method by first passing the method call up the tree.

Subclassing can be a rather complex process, especially for such a complex object as a control, although it can be very useful and powerful.

Perspx
Wow! Thanks very much for this great answer! I have put the code in that I want to use but, I get an error with the code I used, I was wondering if you could help me solve the problem. Here is the code. http://fwdr.org/w3cr .The Problem I have is that i get an error saying 'rowIndex' is un-declared but I don't know what to declare as (I mean whether it is an NSArray etc.). I wondered if you could help, seeing as though it is why I had to subclass NSOutlineView in the first place. Thanks Again for the Great Answer. And sorry about this long comment.
Joshua
That was what I was trying to say at the beginning of my post - if you look in the docs, outlineView:willDisplayCell:forTableColumn:item: is a delegate method; therefore if you only want to override this method then you do not need to subclass NSOutlineView; you can simply make your controller class a delegate of your NSOutlineView, and then implement that method there. As for your sample, you want to call rowForItem: on the outline view, passing anItem as the argument to retrieve the row index.
Perspx
The reason I am trying to sub-class NSOutlineView to do this is because it said to do so where I got the code from (http://www.cocoadev.com/index.pl?AlternatingRowColors)
Joshua
If you're only implementing the outlineView:willDisplayCell:forTableColumn:item: method, you don't need to subclass NSOutlineView. If you are looking at the Apple code example further down the page where you have to do actual drawing then you need to subclass NSOutlineView.
Perspx
The code I was using was the code at the top of the page. If i did not sub-class NSOutlineView for that how would I need to change the code?
Joshua
Thanks, I didn't notice that code near the bottom of the page, So I had a go at using the Apple Code with the Sub-Class and it just about worked but I get a warning saying ''MyOutlineView' may not respond to '-drawStripesInRect:''. Do you know how I might fix this problem?
Joshua
Did you declare the drawStripesInRect: method in your NSOutlineView subclass? Check the method declaration and make sure to declare it in your class header file.
Perspx
What would I put in the header file to declare it?
Joshua
You would simply declare it in the class implementation like any other class method.
Perspx
How would you declare it? Would it be a bit like this … NSArray *objectArray; but saying drawStripesInRect and NS Something?
Joshua
You'd declare it as - (void) drawStripesInRect:(NSRect)clipRect after the curly braces but before the @end.
Perspx
Ahh I See, That Now gets rid of the error but now I get another error on the line #import "MyOutlineView.h" saying 'syntax error before 'AT_NAME' Token'.
Joshua
Sorry, I missed out the semicolon at the end of the declaration. It should be - (void) drawStripesInRect:(NSRect)clipRect;
Perspx
No Problem, All the code works now but It has not affected the Outline View, is there something i need to do to connect the two so they will work?
Joshua
Perhaps you should start a new question? It will attract a larger audience and you can get a specific answer to what you want.
Perspx
Perhaps So, what do you think would be the best title to attract a larger audience?
Joshua
That's up to you - I was just saying that your question has deviated from your original question, and is more specific so perhaps it would be better placed as a new question.
Perspx
The New Question Is Here, http://stackoverflow.com/questions/993465/nsoutlineview-not-doing-what-it-has-should-do-in-its-subclass .
Joshua