Placement of NSAlert-view?

Discussion in 'Mac Programming' started by Danneman101, Jan 22, 2011.

  1. Danneman101 macrumors 6502

    Joined:
    Aug 14, 2008
    #1
    I'm using an NSAlert to alert the user of some stuff:

    Code:
    - (void)fn_ShowPopup: (NSString*)str_Title: (NSString*)str_Message
    {
    	NSAlert *alertView = [NSAlert alertWithMessageText:str_Title defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:str_Message];	
    	[alertView runModal];	
    }
    
    This view, however, appears in the middle of the screen rather than centered on the actual app window. Is there a way to manage where the NSAlert will appear in relation to the app's window?

    Preferably I would like to implement the same behavior seen in many of apple's apps, where the alert-view appears to drop down from the top of the current app and then sticks to that place.
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
  3. Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #3
    Well, actually I've been trying that method out as well, but got the same result as the other one.

    MyController.m
    Code:
    #import "MyAppDelegate.h"
    ...
    MyAppDelegate *myAppDelegate;
    ...
    - (void)fn_ShowPopup: (NSString*)str_Title: (NSString*)str_Message
    {		
       NSAlert *alert = [[NSAlert alloc] init];
        [alert addButtonWithTitle:@"OK"];
        [alert setMessageText:str_Title];
        [alert setInformativeText:str_Message];
        [alert setAlertStyle:NSInformationalAlertStyle];
    // ALT 1: Trying to attach it to appdel>window
        [alert beginSheetModalForWindow:myAppDelegate.window modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];	
    // ALT 2: Trying to attach it to a webview (property of current class, not appdelegate)
        [alert beginSheetModalForWindow:webView modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];	
    }
    
    Both alternatives display a modal window much like the runModal-function.

    However, on your suggestion I gave it another shot, this time placing the code inside the appdelegate on applicationDidFinishLaunching, and this did in fact get the desired effect (an alert-sheet).

    MyAppDelegate.m
    Code:
    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
    {
       NSAlert *alert = [[NSAlert alloc] init];
        [alert addButtonWithTitle:@"OK"];
        [alert setMessageText:@"My title"];
        [alert setInformativeText:@"My text"];
        [alert setAlertStyle:NSInformationalAlertStyle];
        [alert beginSheetModalForWindow:window modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
    }
    
    This to my limited knowledge seems to indicate that my reference to the "window"-property (ie. the app window) in MyController.m is faulty somehow. What am I missing in order to get this sheet-effect to work properly in MyController.m instead of just showing a free modal window?
     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    1) Does window point to a valid NSWindow instance?

    2) Do you actually have a method alertDidEnd:returnCode:contextInfo: in the object you pass as the modalDelegate:?
     
  5. Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #5
    1) Yes, I believe it does. Just in case, here is the code:

    MyAppDelegate.h
    Code:
    ...
    @property (assign) IBOutlet NSWindow *window;
    ...
    
    MyAppDelegate.m
    Code:
    ...
    @synthesize window;
    ...
    
    And the "window" is hooked up in interfacebuilder.


    2) Well, no. I realize it won't close the window until I implement it, but the code actually executes without it and does display the correct type of alertview when run in MyAppDelegate. But I'll add it quickly to my project and return with an answer in a moment...
     
  6. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #6
    Re 1): Has the window actually been initialised at that point? Check if window==nil and log a message if it is nil. If this is the case I suggest you need to move your code to awakeFromNib...
     
  7. Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #7
    2) Ok, I tried a simple alertDidEnd and still get the wrong type of alertview in MyController.m

    Code:
    - (void) alertDidEnd:(NSAlert *) alert returnCode:(int) returnCode contextInfo:(int *) contextInfo
    {
    	NSLog(@"alert close");
    }
    
     
  8. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #8
    See my post above. If window==nil you will always get this behaviour.
     
  9. Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #9
    Sorry, I realized I missed that bit of code in the second post. Should be:

    MyController.h
    Code:
    #import "MyAppDelegate.h"
    ...
    MyAppDelegate *myAppDelegate;
    ...
    - (void)awakeFromNib 
    {	
    	myAppDelegate = [[MyAppDelegate alloc] init];
    }
    ...
    - (void)fn_ShowPopup: (NSString*)str_Title: (NSString*)str_Message
    {		
       NSAlert *alert = [[NSAlert alloc] init];
        [alert addButtonWithTitle:@"OK"];
        [alert setMessageText:str_Title];
        [alert setInformativeText:str_Message];
        [alert setAlertStyle:NSInformationalAlertStyle];
    // ALT 1: Trying to attach it to appdel>window
        [alert beginSheetModalForWindow:myAppDelegate.window modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];	
    // ALT 2: Trying to attach it to a webview (property of current class, not appdelegate)
        [alert beginSheetModalForWindow:webView modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];	
    }
    
    So the window *should* be initiated - but is not. When I checked if window was nil or not in the fn_ShowPopup-function, it turns out it is still nil. Hmmm, then I must have referenced the myAppDelegate.window wrong in MyController.m somehow, since using window from the AppDelegate does work. Any ideas where I go wrong?
     
  10. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #10
    Your appDelegate that you are creating via alloc/init in awakeFromNib is your problem: that is a) not the app delegate, just an object with a convenient name, b) going to be linked to anything in a nib as you are creating it instead of letting it get deserialised from the nib.

    You need to have the app delegate object created in the nib, correctly set as the app delegate and linked to the window. You then access that via the delegate property of the NSApplication singleton object.

    I would say that this represents a fundamental lack of understanding about the basics of the Cocoa application architecture. I suggest you take a step back and do some reading on the subject...
     
  11. Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #11
    1) So I'm actually creating a NEW instance of MyAppDelegate, which contains none of the linkages etc. set up to the instance that gets created automatically when the app is setup?

    2) I think I do have the App Delegate set up correctly in xib, and linked to the window. In "Connections", the appdelegate has the following settings:
    "Outlets"
    window <-> Window (MyAppDelegate)
    "Referencing Outlets"
    delegate <-> Files Owner

    If that is correct, my fault seems to be that I don't yet know how to properly access the window via the delegate property of the NSApplication singleton object, and I must indeed read up on that.


    I actually realized that there was a much simpler solution that totally slipped my mind. I could simply create another window-property in MyController's xib-file and attach the window to it :p Works fine.

    Still, I want to understand how to access objects and properties properly from other classes, and apparently I had it all wrong. I'll read up on the subject, and if you do have any other suggested readings don't hesitate to educate me :)

    Thanks again for your help :)
     
  12. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #12
    Yes. Unless the class is carefully and intentionally code to be a singleton object alloc/init always creates a new object.

    As for accessing the app delegate object, as per the documentation use NSApp to get a reference to the NSApplication object and use the delegate property
     
  13. Danneman101 thread starter macrumors 6502

    Joined:
    Aug 14, 2008
    #13
    Alright, NSApp is the next step on the path then :) Thanks again, Robbie!
     

Share This Page