3

I have a Mac OS X app written in objetive-c Cocoa. You can see most of the code in this previous question. Essentially you click a button on the main window (the app delegate) and it opens another window where the user can enter information.

In the following code (that gets called when the user press the button in the app's main window)

- (IBAction)OnLaunch:(id)sender {

    MyClass *controllerWindow = [[MyClass alloc] initWithWindowNibName:@"pop"]; 
    [controllerWindow showWindow:self];

    NSLog(@"this is a log line");
}

The NSLog line gets printer immediately after I called showWindow. Is there any way to wait until controllerWindow is closed to continue with the NSlog?

The reason for this is that the user set's a value on the new window I opened and I need to collect that value on the same OnLaunch so I need to wait.

I know that modal windows are bad form in Mac, but I have no control over this feature.

I've tried with

[NSApp runModalForWindow:[controllerWindow window]];

and then setting the popup window to

[[NSApplication sharedApplication] runModalForWindow:popupwin];

and it works but then the focus never gets passed to the main window anymore Thanks!

Community
  • 1
  • 1
Mr Aleph
  • 1,887
  • 5
  • 28
  • 44
  • I'll answer my own question: The answer is [Here](http://stackoverflow.com/questions/6429365/how-to-show-sheet-from-separate-nib) – Mr Aleph Sep 27 '11 at 16:39

2 Answers2

5

If you want the window to be modal for your application, use a sheet: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Sheets/Tasks/UsingCustomSheets.html

However, there is no way to suspend execution of a method while the sheet is displayed, this would be tantamount to blocking the current run loop. You would have to break you code into the begin and end methods as described in the linked documentation.

Here are the steps you need to follow:

  • In TestAppAppDelegate create an NSWindow outlet to hold your sheet and an action to dismiss the sheet
  • Create a nib with an NSWindow as the root object. I think you already have this in "pop". Set the Visible at Launch option to NO (this is very important)
  • Set the file's owner of this nib to TestAppAppDelegate and connect the window to your new outlet, and the close button to your new action
  • In your method to launch the sheet (OnLaunch), use the following code:

(ignore this it's to make the code format properly!)

if(!self.sheet)
  [NSBundle loadNibNamed:@"Sheet" owner:self];
    
[NSApp beginSheet:self.sheet 
   modalForWindow:self.window 
    modalDelegate:self 
   didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) 
      contextInfo:nil];
  • Your close button action should be [NSApp endSheet:self.sheet];
  • Your didEndSheet: method should be [self.sheet orderOut:self];
Cœur
  • 37,241
  • 25
  • 195
  • 267
jrturton
  • 118,105
  • 32
  • 252
  • 268
  • OK, would you mind giving me an example? I tried reading already the documentation for sheets and I even more confused. Keep in mind that I need 2 texfields and 2 buttons. I tried with an alert but it allows me to add only one text field. – Mr Aleph Sep 27 '11 at 12:44
  • The link I gave shows how to make a custom sheet using your own nib. In the nib you would set file's owner to your calling class and have an outlet on there for the top level object in the nib, plus actions for any of the buttons. You wouldn't have a separate controller class. If you update your question with what you have so far I will try to help but I'm not here to write your code for you! – jrturton Sep 27 '11 at 12:53
  • I didn't ask you to write code, I just ask you for an example of how to implement this with what I have, which by the way I posted. The code at the Apple dev site doesn't make any sense to me and I can't seem to be able to convert it to what I need. since I am I came to stackoverflow to get help. While I do appreciate the "try this" and "try that" kind of answers for most cases I do NOT understand why is it that to get a window modal on Mac OS is so damn complicated. I guess my expectations of the answers here were wrong. thanks anyway. – Mr Aleph Sep 27 '11 at 14:07
  • which points to the same apple dev link you gave me and an outdated site that doesn't have code that work with the current xcode. I'm trying to understand what you want me to do but I can't. I have an 2 xibs in my app (see code in full in this [previous question](http://stackoverflow.com/questions/7559449/passing-the-stringvalue-of-a-textfield-from-one-class-to-another)) how can I use the 2nd xib as a sheet? so far I haven't found the answer on any of your links – Mr Aleph Sep 27 '11 at 14:27
  • Even when I try: [NSApp beginSheet:popWindow.RelativePopup modalForWindow:[self window] modalDelegate:self didEndSelector:nil contextInfo:nil]; I go nowhere. – Mr Aleph Sep 27 '11 at 14:31
  • Looking at the docs a bit more closely, you are right and they are pretty hard to follow. I've updated my question with some sample code. – jrturton Sep 27 '11 at 19:43
  • Thanks. I figured out already. You also need to add `[NSApp runModalForWindow:[controllerWindow window]];` in order to make it modal – Mr Aleph Sep 27 '11 at 20:43
-1

You can use UIVIew method animateWithDuration:delay:options:animations:completion: to accomplish this.

You said you want the next line to execute once the window is closed, rather than after it is opened. In any case, you may end the OnLaunch method this way:

- (IBAction)OnLaunch:(id)sender {

    MyClass *controllerWindow = [[MyClass alloc] initWithWindowNibName:@"pop"]; 

    [controllerWindow animateWithDuration:someDelay:options: someUIAnimationOption
    animations:^{
        [controllerWindow showWindow:self]; // now you can animate it in the showWindow method
    }
    completion:^{
         [self windowDidFinishShowing];  // or [self windowDidFinishDisappearing]
    }
}

- (void) windowDidFinishShowing {
    NSLog(@"this is a log line");
}
Jim
  • 5,940
  • 9
  • 44
  • 91
  • Won't this completion block get called on when the new window animation is done? What he wants is when the window is closed, not done animating. – fearmint Sep 26 '11 at 19:59
  • Yes, the main point is to separate the operation of opening the window from the completion of an event, like the animation completion event. Wherever he initiates the close of the window should call windowDidFinishShowing. If he wants it to happen after the window has actually dissapeared, then I recommend using this completion event with the animation method. – Jim Sep 26 '11 at 20:03
  • By the way, I had to interpret what you are asking. I don't think there is a state for a window called "closed", but I could be wrong. So I assume you are referring to a view that has changed state in some way, like being hidden, or it's size has been reduced to zero. (I program using IOS, so I don't know about more than one window, but with IOS, you can "open" and "close" any number of views.) – Jim Sep 26 '11 at 20:09
  • Im having trouble figuring out the `animateWithDuration:someDelay:options: someUIAnimationOptionanimations` also `somedelay`, whats that? milliseconds, seconds? what if the use takes 10 minutes to close the window? – Mr Aleph Sep 26 '11 at 20:09
  • @jim No, it's a simple thing: you open the new window and wait until the user closes it. Simple and clear. Like an open file dialog, you wait until the user closed it to get the value of the filename – Mr Aleph Sep 26 '11 at 20:11
  • You need to execute the windowDidFinishShowing after the user actually closes the window. Execute it from within the code that actually causes the window to close. The animation method only affects how the drawing transition is done (like sliding views in and out). Does the user click a button when he is done entering data? Does he hit a return button? If he hits return, then you will probably be executing textFieldShouldReturn:, part of the UITextFieldDelegate protocol. – Jim Sep 26 '11 at 20:20
  • This answer is not relevant for a mac application. – jrturton Sep 26 '11 at 21:28