Displaying a Cocoa Window as a Sheet in Xcode 4 (OSX 10.7.2) with ARC
Asked Answered
B

2

35

I'm trying to get a Login Window to display as a sheet from my MainWindow, but whenever I try to implement the AppKit methods an error always pops up for various indistinguishable reasons.

None of the online guides out there are working, when i apply their code / adapted classes to my own project they never work.

Most of the guides are heavily outdated, including the Apple Documentation. And none of them seem to be compatible with Automatic Reference Counting. Or the Xcode 4 interfaces.

Would someone be able to detail for me in full a guide, for the simplest way of displaying a sheet following a button press on the MainWindow.

Feel free to ask for more information if you need it.

Baram answered 8/11, 2011 at 23:49 Comment(0)
S
93

Tutorial for Xcode 4

Create new project and add the following to AppDelegate.h and AppDelegate.m.

AppDelegate.h

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate> {

    IBOutlet NSPanel *theSheet;
}

@property (assign) IBOutlet NSWindow *window;

@end

AppDelegate.m

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;

- (IBAction) showTheSheet:(id)sender {

    [NSApp beginSheet:theSheet
       modalForWindow:(NSWindow *)_window
        modalDelegate:self
       didEndSelector:nil
          contextInfo:nil];

}

-(IBAction)endTheSheet:(id)sender {

    [NSApp endSheet:theSheet];
    [theSheet orderOut:sender];

}

@end

Open the MainMenu.xib.
Use the existing NSWindow.
Make it visible using the following button:

Xcode

Create one new NSPanel.
Add the appropriate NSButtons.

Xcode

Connect Close to the App Delegate.

Xcode

And select endTheSheet.

Xcode

Connect Open to the App Delegate.

Xcode

And select showTheSheet.

Xcode

Connect the App Delegate to the new NSPanel.

Xcode

And select theSheet.

Xcode

Select the NSPanel and disable Visible At Launch. (Essential step!)

Xcode

Now hit run and enjoy the result:

Xcode

Strength answered 9/11, 2011 at 1:2 Comment(6)
You are flipping amazing! those screenshots are really nice and helpful, thank you so much.Baram
Question to Anne on the above sample: if I would add an NSTextField to the sheet, how could I transfer text back and forth between the sheet and its parent window ?Kalahari
@Kalahari and David: It would make sense to create a separate question on StackOverflow. In short, you'd simply add a NSTextField i-var or @property, marked with IBOutlet. When the sheet is closed, you may want to additionally copy the contents to a different i-var or property of type NSString*. Or be extra careful about not releasing the text field.Dominiquedominium
Your screen shots remind me of the work of a Jedi Master. Thanks :)Mccready
So much work and it is all now declared deprecated in Yosemite.Merras
@Strength thanks for your answer, I have one question. I implement the same and working well. but after showTheSheet, close button of main window Disabled and also cmd + Q ( menu -> quit ) also not working. any Suggestion ?Stonewall
C
6

Things have changed in SDK 10.10 - the calls are simpler to understand I think. A parent window is in charge of launching a child NSWindow as a sheet - and then you pass this child NSWindow to NSApp to run modally. Then do the opposite to unwrap.

Displaying sheet

To display the sheet instead of calling:

[NSApp beginSheet:theSheet
   modalForWindow:(NSWindow *)_window
    modalDelegate:self
   didEndSelector:nil
      contextInfo:nil];

You now call on the parent window:

(void)beginSheet:(NSWindow *)sheetWindow
 completionHandler:(void (^)(NSModalResponse returnCode))handler

And then to run the sheet as in modal loop, you also have to call NSApp with:

- (NSInteger)runModalForWindow:(NSWindow *)aWindow

Closing Sheet

To close the sheet, call on the parent window:

- (void)endSheet:(NSWindow *)sheetWindow

Which causes the completionHandler from the above call to fire, - in which you can put a call to stop running the modal window by calling NSApp with:

- (void)stopModalWithCode:(NSInteger)returnCode

Full example

@implementation AppDelegate

@synthesize window = _window;

- (IBAction) showTheSheet:(id)sender {

    [_window beginSheet: theSheet
         completionHandler:^(NSModalResponse returnCode) {
             [NSApp stopModalWithCode: returnCode];
         }];

    [NSApp runModalForWindow: theSheet];

}

-(IBAction)endTheSheet:(id)sender {
    [_window endSheet: theSheet];
}

@end
Calvert answered 28/4, 2015 at 18:27 Comment(2)
If this shouldn't be here (as the title is specific to xcode 4, please let me know before downvoting and I'll remove it)Calvert
It needs to be said that the sheet window must be hidden before beginSheet is called otherwise it looks like a sheet but is not attached.Merras

© 2022 - 2024 — McMap. All rights reserved.