views:

417

answers:

3

I have made a window with an NSOpenGLView that I am rendering openGL content into.

I want to add some buttons and text fields to the view: I can add NSTextFields and NSButtons using interface builder (or code) but they do not appear.

NSOpenGLView is documented as not being able to have sub views, so I then made my own CustomGLView by deriving directly from NSView and implementing the code to create and use a NSOpenGLContext in it. But the subviews are still not appearing :- the OpenGL context paints over them.

On Windows this problem does not exist:- Windows used to host OpenGL MUST have the WS_CLIPCHILDREN and WS_CHIPSIBLINGS styles set ensuring that any peer, or sub children (views) will not be obscured by the OpenGL surface.

How do I get subviews to display over a NSView thats drawing using OpenGL ?

A: 

NSOpenGLView cannot have subviews according to the documentation. Even if you subclass the NSOpenGLView, that will change nothing.

What you can do is to create a NSView that will hold both the NSOpenGLView and the NSTextField. You then overlap them in the right order to make one draw atop the other.

Laurent Etiemble
I didn't subclass the NSOpenGGView - i created an entirely new NSView subclass that I then added code to to get an NSOpenGLContext.
Chris Becke
I tried that in Interface Builder: Created a generic content NSView, and give it a NSOpenGLView and a NSButton. It doesn't matter which way around I position them, the NSOpenGLView always paints over the NSButton / NSTextField.
Chris Becke
A: 

I'm not heavily into OpenGL yet, but it's my understanding that you can accomplish the visual effect of subviews with Quartz Extreme using layer-backed views; however, those may be problematic. Since subviews are not supported directly, any solution is liable to be a hack.

Indeed, the solution in that link actually hacks a second window to appear over your OpenGL display, the second window displaying the Cocoa views you desire.

The following code (from the above link) is something I've not tested (again not being an OpenGL guy by nature -- yet), but appears like a fairly clever approach:

// This is the GL Window and view you already have
glWindow = [[GLWindow alloc] initWithContentRect:windowRect];
glView = [[[GLView alloc] initWithFrame:NSMakeRect(0, 0, windowRect.size.width, windowRect.size.height)] autorelease];
[glView translateOriginToPoint:NSMakePoint(glView.bounds.size.width/2, glView.bounds.size.height/2)];
[glWindow setContentView:glView];

// And here's your transparent UI window
uiWindow = [[TransparentWindow alloc] initWithContentRect:windowRect];
uiView = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, windowRect.size.width, windowRect.size.height)] autorelease];
[uiView translateOriginToPoint:NSMakePoint(uiView.bounds.size.width/2, uiView.bounds.size.height/2)];
uiView.wantsLayer = YES;

[uiWindow setContentView:uiView];
[glWindow addChildWindow:uiWindow ordered:NSWindowAbove];

Again, I've not tested this, but it looks like it will get you the visual effect you desire.

John Rudy
+1  A: 

You have 2 choices:

  1. Create a window just for the text field. Add as a child window of the one hosting the OpenGL view. Major downside is you have to manage positioning it correctly if the Open GL view is moved.

  2. Set up your view hierarchy like so:

    • Layer-backed view
      • Layer-hosting view whose layer contains an OpenGL layer
      • Text field
Mike Abdullah
I don't quite know what is meant by a layer backed view.http://developer.apple.com/mac/library/samplecode/LayerBackedOpenGLView/ doesn't imply that much special needs to happen to the hosting view at all. Perhaps its implicit in the buffering selected. All you need to do really is:`[openGLView setWantsLayer:YES]`
Chris Becke