9

How do I put a window in a separate NIB, give it its own NSWindowController, make it slide out as a sheet?

(Is this a typical thing to do with sheets?)

I am trying to show a custom sheet (a window that slides down from the title bar of the parent window) from my main window. What I'm trying to do is standard, I think, but I cannot find clear examples or explanations for how to do exactly what I want.

What I am trying to do:

  1. My app delegate owns the main window, which has a button to open a "settings" sheet.
  2. The "settings" sheet:
  • is in a separate NIB.
  • has file owner set to class SettingsWindowController, which is subclass of NSWindowsController
  • When user clicks "settings", I am trying to use Apple's [sample code][1]
  • - (void)showCustomSheet: (NSWindow *)window
    // User has asked to see the custom display. Display it.
    {
        if (!settingsSheet) 
        //Check the settingsSheet instance variable to make sure the custom sheet does not already exist.
            [NSBundle loadNibNamed:@"SettingsSheet" owner: self];
            //BUT HOW DOES THIS MAKE settingsSheet NOT nil?
    
        [NSApp beginSheet: settingsSheet
                modalForWindow: window 
                modalDelegate: self 
                didEndSelector: @selector(didEndSheet:returnCode:contextInfo:) 
                contextInfo: nil]; 
    
        // Sheet is up here.
    
        // Return processing to the event loop
    } 
    

    Please excuse the following simplistic and numerous questions:

    • When I call, loadNibName:owner:, I don't want owner to be self, because that makes my app delegate the owner of the "MyCustomSheet" - that's what my SettingsWindowsController is supposed to be for. However, I don't know how make SettingsWindowsController the owner in this method.
    • If my sheet has "Visible at launch" checked, then loadNibName:owner: immediately displays the window as a normal window, not as a sheet that slides out from the main window.
    • If my sheet has "Visible at launch" not checked, then beginSheet:modalForWindow:etc causes "Modal session requires modal window". I'm pretty sure this is because I made the Nib's owner self (as I mentioned already).
    • In the sample code, I don't know how the Nib named @"SettingsSheet" is "associated" with the instance variable settingsSheet - but they apparently are related because the code checks first: if (!settingsSheet) (I've marked this with comment //BUT HOW DOES THIS MAKE settingsSheet NOT nil?)

    Thanks for your patience in reading all this!

    Anoop Vaidya
    • 46,283
    • 15
    • 111
    • 140
    stifin
    • 1,390
    • 3
    • 18
    • 28

    1 Answers1

    10
    1. Create an instance of SettingsWindowController, use initWithWindowNibName:

    2. You don't want it visible at launch.

    3. See 1.

    4. Your instance variables will be available to SettingsWindowController

    Matt
    • 74,352
    • 26
    • 153
    • 180
    Grady Player
    • 14,399
    • 2
    • 48
    • 76
    • THANK YOU! This is exactly what I needed! Would it have been too much to ask Apple to have done something this simple in their documentation? (Their sample code somehow doesn't seem to require the `initWitWindowNibName`.) – stifin Jun 21 '11 at 20:28
    • lol, yeah sometimes they have companion guides that get into this stuff, but if you are missing a couple of little pieces it can be hard to put together. – Grady Player Jun 21 '11 at 20:30
    • I tried to build up your example from scratch and was still getting the "Modal session requires modal window" error. I then checked everything bit-by-bit, line-by-line, in code and IB, against your example and couldn't see any difference. Finally, I put your 2 asserts in and saw that it failed on `assert (window)`. Do you know what makes this assertion pass or fail? I've obviously missed something somewhere – stifin Jun 21 '11 at 22:06
    • did you set the outlets for window in the IB? – Grady Player Jun 21 '11 at 22:07
    • also did you set the file owner's class in IB? – Grady Player Jun 21 '11 at 22:07
    • brilliant! Okay, it now works after I ctrl-dragged from the file's owner in the sheet's Nib to the window! I'm definitely inexperienced with all this but it's not the first window in my real-world app... yet, I don't recall having to do this before...... is this something I just have to remember to do all the time, or only in these situations? – stifin Jun 21 '11 at 22:23
    • If I put a close button on the sheet, I call: -(IBAction)close:(id)sender { [[sender window] orderOut:nil]; [NSApp endSheet:[sender window]]; } I don't know if this is correct, but it does dimiss the sheet. – stifin Jun 22 '11 at 18:00
    • to your previous question(and i thought i responded to it), you normally start with a project that has the outlets already set up, but if you are making your own, then you will have to. as for the second, I don't see any problem with that. – Grady Player Jun 22 '11 at 21:03
    • yes, it was your previous comment that made me find that small but critical step of setting the outlet. thanks again! – stifin Jun 22 '11 at 23:17
    • @GradyPlayer, if I turn breakpoint exception on in your project I will see: `objc[36178]: EXCEPTIONS: throwing 0x1e4148fd8 (object 0x1e4144fd0, a NSException) objc[36178]: EXCEPTIONS: searching through frame [ip=0x7fff868db540 sp=0x7fff5fbfcf60] for exception 0x1e4148fb8 objc[36178]: EXCEPTIONS: catch(NSException) objc[36178]: EXCEPTIONS: unwinding through frame [ip=0x7fff868db540 sp=0x7fff5fbfcf60] for exception 0x1e4148fb8 objc[36178]: EXCEPTIONS: handling exception 0x1e4148fb8 at 0x7fff868db505 objc[36178]: EXCEPTIONS: finishing handler` Do you know something about them? Thanks a lot. – alexchernyy Sep 22 '13 at 15:23
    • @alexchernyy, I don't, but I will investigate next week if I think about it. – Grady Player Sep 23 '13 at 02:11
    • Any chance you could re-upload your example? Thanks! – Rotsiser Mho May 28 '14 at 04:03
    • 1
      @RotsiserMho I didn't know the link was bad, I will try – Grady Player May 28 '14 at 15:22