Objective-C modal Window using sheets and Panels

Adding a modal sheet to a window in objective-C isn’t highly complicated however there are a number of issues to watch for that can leave you scratching your head. Most of the examples I’ve found on the internet point to an older useModal:¬†(*window) function which is deprecated. From what i’ve read, the correct manner for using a modal dialog is to display a sheet that scrolls down from the menu bar and takes modal control. There are numerous examples of this in System Preferences:

Implementing this in an application coded with objective-C isn’t relatively complicated ¬†however missing a particular setting can leave you with numerous errors or causing the application to fall back to the debugger.

Create a new Project in Xcode and select a Cocoa Application, enter a simple name and create the project. As per default an empty window application will be created, an IBAction should be created in the AppDelegate (to be used to display the modal window) this can be linked to a button or a menu bar action. Right click in the project view and select New Files… and add a new Objective-C class and ensure that it subclasses NSWindowController. Again, right click in the project view and add a Window from the User Interface section, open this up in the User Interface editor and delete the default window that it comes with. From the object library add a Panel to replace the default window that was in the nib. Whilst still in Interface Builder select the File’s Owner and change it’s custom class to the class added earlier that is a subclass to NSWindowController. Then Right click->drag from the File’s Owner to the panel and link to it’s window object. In the AppDelegate.h add the header of the class created earlier and create a pointer to an instance of it. In the implementation of the AppDelegate create the IBAction implementation and add the following code:

yourClassNamePointer = [[YourClassName alloc] initWithWindowNibName:@”NibName”];

[[NSApplication sharedApplication] beginSheet:[yourClassNamePointer window]

modalForWindow:[self window]

modalDelegate:yourClassNamePointer

didEndSelector:nil

contextInfo:nil];

This simple two lines of code (spread over more to make it more readable) will allocate memory for your class with a nib and pass the pointer address to your variable. Then it will use the NSApplication (the main loop class for most applications) and have it attach a sheet to a window and pass all modal functionality to it. Unless you’ve skipped a step running this and having something call the IBAction will display the sheet, however it won’t be connected to the initial window. Stop the application through Xcode and open up the panel window in Interface Builder, and from the Objects menu select the “Panel-Window” and select the attributes inspector. From this menu you will find that Under Window -> Behaviour -> Visible At Launch [X] is selected, deselect this and re-run your code and you’ll find the modal window is attached to the main window.

 

Finally, to get rid of the modal window add a button to the panel nib and link it up to an IBAction in your custom class. Add the following code:

[NSApp stopModal];

[[self window]orderOut: nil];

[[NSApplication sharedApplication] endSheet:[self window] returnCode:NSOKButton];

 

This will turn off being Modal, close the modal window and return back the main screen.

3 thoughts on “Objective-C modal Window using sheets and Panels”

  1. Worked like a treat once I discovered that I had to send any additional info after the alloc/init but before the beginSheet if the info was to be received and acted upon. In my application I was able to convert my preferences window into a preferences sheet. Thanks.

    ….Jeff

  2. Thanks so much for this. I was fighting with modal sheets for several hours. I finally got it working, but I was resorting to a single xib for my 2 windows. Your tutorial made it much cleaner and very painless to implement.

Leave a Reply

Your email address will not be published. Required fields are marked *