How to show a NSPanel as a sheet

2019-04-07 01:48发布

I'm trying to show a NSPanel as a sheet. I'm naively doing something along those lines:

SheetController *sheetController = [[[SheetController alloc]
                                      initWithWindowNibName:@"Sheet"] autorelease];

[[NSApplication sharedApplication] beginSheet:sheetController.window 
                               modalForWindow:self.window
                                modalDelegate:self
                               didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) 
                                  contextInfo:nil];

For some reason that eludes me, this isn't working. When this part of the code is called, the sheet momentarily flashes (because of the autorelease message). The sheet is never hooked to window.

If anyone can point me to where I can find more information, that would be very appreciated.

3条回答
不美不萌又怎样
2楼-- · 2019-04-07 01:54

Yes, you need to own this controller for as long as you want it to continue functioning. You can't just create it, autorelease it, and let it die—you need to hold onto it for as long as you need it.

查看更多
Evening l夕情丶
3楼-- · 2019-04-07 01:57

Don't forget that if you're trying to run this as a "modal" sheet (i.e. it takes over the app until the user dismisses it), you'll need to push a new run loop.

What you've done is shown the sheet, and then not pushed a new loop, so the OS just shows the sheet, sees there's no reason to keep it running, and thus shuts it down and resumes execution on the next line:

I typically do sheets the following way:

- (id)showPanelModalAgainstWindow: (NSWindow *)window
{
   [[NSApplication sharedApplication] beginSheet: panelToShow
                modalForWindow: window
                modalDelegate: self
                didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:)
                contextInfo: nil];

   [[NSApplication sharedApplication] runModalForWindow: panelToShow];
   if (m_returnCode == NSCancelButton) return nil;
}


- (void)sheetDidEnd:(NSWindow *)sheet
         returnCode:(int)returnCode
        contextInfo:(void  *)contextInfo
{
    UNUSED(sheet);
    UNUSED(contextInfo);
    m_returnCode = returnCode;
}

Then, in your accept and/or cancel button routines:

- (IBAction)continueButtonClicked:(id)sender
{
    UNUSED(sender);
    [[NSApplication sharedApplication] stopModal];
    [createAccountWizardPanel orderOut: nil];
    [[NSApplication sharedApplication] endSheet: createAccountWizardPanel
                                       returnCode: NSOKButton];

}

I'm sure there is a slightly less code-y way of doing this, but I've not looked to deeply into it, because this way works perfectly fine thus far ....

Previous comments about the lifetime of the controller and panel objects are also relevant -- be sure to understand exactly what objects you need for what lifetimes when showing a modal panel.

查看更多
爷、活的狠高调
4楼-- · 2019-04-07 02:11

This sounds like a classic case of having checked the "Visible at Launch" box for the panel in IB. Turn that off.

查看更多
登录 后发表回答