XCode: Display window as modal

The following code works fine with XCode Version 5.1. It's the goal to create a window that appears modal on a main window by sliding in from top by using Objective C. If you like to use Swift look at the correspondent swift article. To display a NSWindow as modal you create a new subclass of NSWindowController . In the same step you can create the *.xib-file for Interface Builder like shown in the image below.

New file image

Before you start coding you should put a Close - Button to your new window. You will need that button to get rid of the window ;-)

Here is the code for header file:

@interface MyOwnWindowController : NSWindowController{
    NSWindow *_mainWindow;
}
-(IBAction)closeButtonPressed:(id)sender;
-(void)beginSheet:(NSWindow *)mainWindow;
-(void)endSheet;
@end

Here is the code for implementation file:

#import "MyOwnWindowController.h"
@interface MyOwnWindowController ()
@end

@implementation MyOwnWindowController
- (id) init{
    //The nibname is the name of the window or *xib-file
    self = [super initWithWindowNibName:@"MyOwnWindow" owner:self];
    if (self) {
    }
    return self;
}

//an IBAction Method for closing the window
- (IBAction)closeButtonPressed:(id)sender {
    [self endSheet];
}

//method to display window modal
- (void)beginSheet:(NSWindow *)mainWindow{
    _mainWindow = mainWindow;
    [NSApp beginSheet:[self window] modalForWindow:_mainWindow modalDelegate:self didEndSelector:@selector(endSheet) contextInfo:nil];
}

//method to remove the myownwindow
-(void)endSheet{
    [NSApp endSheet:[self window]];
    [[self window] orderOut:_mainWindow];
}
@end

In your delegate-file of the mainwindow the subclass is allocated and initialized. To display the window you call beginSheet.

_myOwnController = [[MyOwnWindowController alloc]init];
[_myOwnController beginSheet:_window];

So far so good! But it doesn't work like expected. The window doesn't slide in from top of the main window and is displayed somewhere on the screen but not in the top middle. And it cost me a lot of time to get the mistake. So pay attention, that you disable the property Visible At Launch in Attribute Inspector for the modal window.

Image Disable Visible At Launch

Please pay also attention that you don't do something like this. Because it can drive you crazy if you have defined IBOutlets oder IBActions in MyMyOwnWindowController e.g. for the Cancel-Button.

- (IBAction)menuItemPressed:(id)sender {
    MyOwnWindowController myOwnController = [[MyOwnWindowController alloc]init];
    [myOwnController beginSheet:_window];
}

When pressing the Cancel-Button or calling another IBAction your application will crash without a helpful error message. That happens when you are using ARC, because myOwnController is autoreleased after calling menuItemPressed:. If you want to use always the same instance of *_myOwnController* you can use an if - command:

- (IBAction)menuItemPressed:(id)sender {
    if (_myOwnController) {
        [_myOwnController beginSheet:[self window]];
    }
    else{
        _myOwnController = [[MyOwnWindowController alloc]init];
        [_myOwnController beginSheet:[self window]];
    }
}

If you didn't create WindowController- and .xib-Files in one step or you have some trouble then check the setting in Interface Builder. At first select Files Owner object and check the identity inspector whether your WindowController-Class is referenced.

Image Class Reference for File Owner Object

Next step check the outlets- and delegate - connection. It has to look like the images below:

Image Outlet Delegate Connoctions with selected Files Owner

Image Outlet Delegate Connoctions with selected Window View

Werbung



comments powered by Disqus

Copyright Dunkel & Iwer GbR | Datenschutzerklärung | Impressum