I want to create an arbitrary canvas in Cocoa; that is, a drawing area where the entire visible area can be drawn on and with scrolling limits chosen by the programmer and have no effect on whether I can draw on the entirety of the visible area. This is similar to how I would do this on Windows and GTK+, and different from the standard NSScrollView in that a) I draw solely in the visible area (so (0, 0) is the origin of the visible area, not the whole document) and b) I am not restricted to the document view frame (so if the document view is smaller than the visible area I can still draw everything in the visible area).

To do this, I'm implementing a subclass of NSClipView to do the drawing and using NSScrollView's document view solely to set scroll extents.

When I override drawRect: in NSClipView, the background of the clip view turns black. The method can be empty, it can defer to super, or it can draw anything; the result is the same. Only by omitting drawRect: does the correct white background color draw.

Now, as hinted here (even though it's about iOS I assume the models are similar enough that the solution would have worked on OS X too), if I override isOpaque to return NO, the background draws correctly. Why? What is different about NSClipView that it can get away with returning YES while still drawing the background?

Or is my approach to implementing this scroll view wrong?

Thanks.

1

There are 1 answers

2
Guilherme Rambo On

isOpaque is basically a hint to the system which says "don't bother rendering anything below this view because it will not be visible anyway".

When you override drawRect: and do nothing or just call super (which probably does nothing in this case), your view has transparent content but It's telling the system to not draw stuff behind It, the result is black.

If you want stuff behind your view to be visible you have to override isOpaque and return NO. If you don't want stuff behind your view to be visible you must make sure It is actually opaque by drawing on all It's surface (even if you just fill It with a background color, white for instance).

So, from what I can understand from your question, you just have to fill your view with white before doing the rest of your drawing:

- (void)drawRect:(NSRect)dirtyRect {
    [[NSColor whiteColor] setFill];
    NSRectFill(dirtyRect);

    // continue drawing the rest of your stuff...
}