Hillegass chapter 12, Challenge "About panel" help needed

Discussion in 'Mac Programming' started by petron, Jul 15, 2009.

  1. macrumors member

    Joined:
    May 22, 2009
    Location:
    Malmo, Sweden
    #1
    Hi,
    I just went through the Challenge in chapter 15.

    When ready with the "cahllenge" I do see the About panel only for a second or so. then it disapear.

    I enable it in the following way in the AppController.m:


    I do not know what I need to do with the outlet...

    IBOutlet NSPanel *aboutPanel;


    I will try to go through it again, but I will appreciate some help.

    BR
    /petron
     
  2. thread starter macrumors member

    Joined:
    May 22, 2009
    Location:
    Malmo, Sweden
    #2
    Now it works...

    I have created new NSWindowController for About Palne and modified the AppController.m in the following way:


    /petron
     
  3. macrumors newbie

    thingsis

    Joined:
    Oct 25, 2008
    Location:
    Germany
    #3
    Hi,

    actually this should be all you need:
    Code:
    -(IBAction)showAboutPanel:(id)sender {
    	[NSBundle loadNibNamed:@"AboutPanel" owner:self];
    	[aboutPanel setTitle:@"Outlet geht!"];
    }
    
    Of course you don't even need to set the title. I just used it to check whether my outlet is working fine. It seems pretty similar to what you are doing. It also works when I assign the result of the NSBundle... to a BOOL var - which makes it even closer to your example.

    thingsis
     
  4. thread starter macrumors member

    Joined:
    May 22, 2009
    Location:
    Malmo, Sweden
    #4
    Hello Tingsis

    It seems that I did something very wrong.

    I do not have any outlet at all, since I did not know how to connect the Outlet "aboutPanel" and to whom to connect.

    Is it declared in the AppController.h like this ?

    IBOutlet NSPanel *aboutPanel;

    I did create a NSwindowController and it works but your solution seems to be more sexy... How did you solved the Outlet connection ?

    /petron
     
  5. macrumors newbie

    thingsis

    Joined:
    Oct 25, 2008
    Location:
    Germany
    #5
    Hi,

    you are almost right ;)
    Code:
    IBOutlet NSWindow *aboutPanel;
    
    It might also work using NSPanel. I do not have the object graph in my head. Also, in InterfaceBuilder you set File's Owner to AppController and connect the aboutPanel Outlet of File's Owner to the actual Panel. Then it should work.

    Thingsis
     
  6. macrumors newbie

    thingsis

    Joined:
    Oct 25, 2008
    Location:
    Germany
    #6
    Hi again,

    I just thought about it again...
    Maybe the problem is not the actual outlet but that you forgot to set a class for File's Owner. Just an idea. Anyway, my post above is still valid I guess.

    Thingsis
     
  7. macrumors regular

    Joined:
    May 27, 2009
    Location:
    Glasgow, Scotland
    #7
    When I did that challenge I didn't have any Outlets I did exactly the same as what happened during the chapter my AppController.h file is:

    Code:
    @class PrefrenceController;
    @class AboutController;
    
    @interface AppController : NSObject {
    	PrefrenceController *prefrenceController;
    	AboutController *aboutController;
    }
    - (IBAction)showPrefrencePanel:(id)sender;
    - (IBAction)showAboutPanel:(id)sender;
    
    @end
    Then I implemented the AboutController file's which opened the nib.

    Hope this helps.

    Stephen

    Edit: Also you make the File Owner the class of your AboutController. Not the AppController.

    Edit again: About adding the outlet you would point it to NSPanel not NSWindow. Should work after that.
     
  8. thread starter macrumors member

    Joined:
    May 22, 2009
    Location:
    Malmo, Sweden
    #8
    Hi,
    I wake up early and needed to try....

    First answer to Stephen..
    Well, both you and I went through the same path with very small differences. It of course works but it is not as sexy as the solution that Thingis made and what the Hillegass had in mind. The Hillegass in his "Challenge" description specified the use of an Outlet. Any way thanks for comments.

    Secondly answer to Thingis..
    Thanks for the tips regarding the "you set File's Owner to AppController"
    After I done this the possibility to connect the Outlet became obvious and possible.

    Here is the actual method, it looks even better if one does not need to change the title of the panel window. It even could be one_liners method if I will drop the NSLog lines.

    The last comment is that I think that you should use the NSPanel and not NSWindow. Both solutions works but the NSPanel is more correct class.

    Any way thanks to all for the help and cooperation. The most important thing is that I learned something new and maybe I understand the subject a bit better.

    /petron
     
  9. macrumors newbie

    Joined:
    Feb 13, 2009
    #9
    I believe that the objective of the challenge was to avoid using an NSWindowController (Hillegass wants you to understand what the controller is doing for you behind the scenes, and how to do it yourself if you don't use one). The purpose of setting the outlet is to enable the AppController to know about and message the about panel. Here is what you do when the user selects the "About" option from the menu:

    1) Load the NIB (but only if it hasn't already been loaded)
    2) Tell the about panel not to release itself when the window is closed
    3) Display the about panel again if it has been closed

    Relevant code:

    AppController.h:

    @interface AppController : NSObject {
    IBOutlet NSPanel *aboutPanel;
    BOOL aboutNibWasLoaded;
    }

    - (IBAction)showAboutPanel:(id)sender;

    AppController.m:

    - (IBAction)showAboutPanel:(id)sender
    {
    if ( aboutNibWasLoaded == 0 ) {
    aboutNibWasLoaded = [NSBundle loadNibNamed:mad:"About" owner:self];
    [aboutPanel setReleasedWhenClosed:NO];
    }

    if ( ! [aboutPanel isVisible] )
    [aboutPanel makeKeyAndOrderFront:self];
    }
     
  10. macrumors 6502

    Joined:
    Jan 3, 2009
    #10
    Yes...makes perfect sense now. I too wondered what the purpose of the outlet was.

    Here's my code....taking most from yours.

    Code:
    -(id) init
    {
    	
    	self = [ super init];
    	nibIsLoaded = NO;
    	return self;
    	
    }
     
    
    
    
    -(IBAction) showPanel: (id) sender
    {
    	if ( nibIsLoaded== NO){
    		{
    		nibIsLoaded = [NSBundle loadNibNamed: @"About" owner: self];
    		[aboutWindow setReleasedWhenClosed:NO];
    		}
    	if ( !nibIsLoaded)
    		NSLog(@"Could not load custom About window");
    		
    	 }
    	
    	else 
    		if ( nibIsLoaded)
    	
    	{
    		NSLog(@"Custom \"About window\" already open");
    		[aboutWindow makeKeyAndOrderFront:self ];
    	}
    }
    	
    -(void) dealloc
    {
    	if (nibIsLoaded == YES)
    	[aboutWindow release];
    	[super dealloc];
    }
     
  11. macrumors newbie

    Joined:
    Oct 4, 2009
    #11
    Hi here is another solution

    First of All, in the Interface Builder :

    - uncheck the 'Release When Close' in the Behavior group of Window menu of the Panel Attributes, in the inspector window.

    - then in the 'File's Owner' identity, just add 'aboutPanel' in the class outlet table view (click plus button); let the type set to id.

    Save your nib file then leave the IB.

    Now, let's examin the code. In bold are the piece i added for this challenge.

    AppController.h
    Code:
    #import <Cocoa/Cocoa.h>
    @class PreferenceController;
    
    @interface AppController : NSObject {
    	PreferenceController *preferenceController;
    [B]	[COLOR="Magenta"]IBOutlet[/COLOR] [COLOR="DarkOrchid"]NSPanel[/COLOR] *[COLOR="Blue"]aboutPanel[/COLOR];
    [/B]}
    - (IBAction)showPreferencePanel:(id)sender;
    [B]- ([COLOR="Magenta"]IBAction[/COLOR])showAboutPanel:([COLOR="Magenta"]id[/COLOR])sender;
    [/B]@end
    
    Now let's see the showAboutPanel method :

    in AppController.m
    Code:
    #import "AppController.h"
    #import "PreferenceController.h"
    
    
    @implementation AppController
    
    - (IBAction)showPreferencePanel:(id)sender
    {...}
    
    [B]- ([COLOR="Magenta"]IBAction[/COLOR])showAboutPanel:([COLOR="Magenta"]id[/COLOR])sender
    {
    
    [COLOR="Olive"]       // if my nib wasn't loaded, my aboutPanel is nil, then that means i
            // have to load the nib[/COLOR]
    	[COLOR="Magenta"]if[/COLOR] (![COLOR="Blue"]aboutPanel[/COLOR]) {
    		[COLOR="Magenta"]BOOL[/COLOR] succes = [[COLOR="Plum"]NSBundle[/COLOR] [COLOR="DarkOrchid"]loadNibNamed[/COLOR]:[COLOR="Red"]@"About"[/COLOR] owner:[COLOR="Magenta"]self[/COLOR]];
    
                    [COLOR="Olive"]// if it succed, Appcontroller becomes the file's owner and
                    // aboutPanel is linked (set in the IB previously in the file's
                    // owner attributes). Otherwise, i get a messsage of failure in
                    // the console[/COLOR]
    		[COLOR="Magenta"]if[/COLOR] (!succes) {
    			NSLog([COLOR="Red"]@"Failure loading the about panel nib file"[/COLOR]);
    		}
    	} [COLOR="Magenta"]else[/COLOR] {
    [COLOR="Olive"]                // the other case is that the panel is existing, so we just
                    // bring it to the front.
    [/COLOR]		[[COLOR="Blue"]aboutPanel[/COLOR] [COLOR="DarkOrchid"]makeKeyAndOrderFront[/COLOR]:[COLOR="Magenta"]self[/COLOR]];
    	}
    }
    [/B]
    @end
    
    If any question...
     
  12. Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #12
    if you've unchecked "Release When Closed" in IB, the above code will not display your custom panel again if it is closed after being once opened. it's ideal to only load the XIB once while simply showing it if has been loaded.

    Code:
    - (IBAction)showAboutPanel:(id)sender
    	{
    	if (!aboutPanel)
    		{
    		NSLog(@"load then display");
    		[NSBundle loadNibNamed:@"About" owner:self];
    		[aboutPanel makeKeyAndOrderFront:self];
    		}
    		else
    		{
    		NSLog(@"only display - has already been loaded");
    		[aboutPanel makeKeyAndOrderFront:self];
    		}
    	}
    
     
  13. macrumors newbie

    Joined:
    Oct 4, 2009
    #13
    Misunderstanding

    Hi.

    I think there's a misunderstanding, Darkroom. When i write :
    it means that i don't want that the panel release itself when it recieving a close message( typically posted when hitting the little red close button on the top left of the panel).

    What does it imply? It implies that when the panel is 'closed', its behavior is not anymore : "Free the memory zone it was using";
    but now its : "Only hide its view".
    It implies too that when the panel is closed, its outlet (translate by the pointer pointing on this object) still pointing on a still used memory zone, and not anymore on a freed memory zony which could contain anything else.


    So then let's resume :
    - the about panel i 've made only hide itself when the close button is hit.

    Next, i did this following step :
    I hope that you understood that my intention was to tell my panel that its futur owner (wathever it will be) will have a outlet pointing on itself. In this case, the file's owner is going to be AppController, so i only have to declare the outlet in its header (which is one Aaron Hillegass directive for this challenge).


    Now let 's run on paper this little piece of code.

    i launch the Raisman app, and my controller class is initialized; during this initialisation, the outlet pointing on my about panel point on nil.
    It happens what happens, and i click on "show about panel" in my menu. It calls the showPanel:sender method (if i've correctly linked my Menu Item Target).
    Let's see what happens:
    First of all i test my AppController outlet aboutPanel :
    . It s the first time i launch this method, so my aboutPanel still pointing on nil, which means (!aboutPanel) = YES, so i go to the statement.
    In this statement, i load the nib, and i link to it AppController.
    If the loading is a succes, my About Panel is unarchived, shown and the file's owner link its outlet aboutPanel to the About Panel. So then the outlet aboutPanel of AppController points now on the About Panel.

    If the nib can't be load if print a message of failure in the console.
    That 's what happens when the showAboutPanel:sender is first called.

    At this point, now my About Panel is in on front and the outlet aboutPanel points on it and it's not nil.

    Then I decide to close the About Panel. After hit the close buton, the panel is no more visible, but it still residing in memory, according the behavior we impose to it. So then my outlet still pointing on a active memory zone well defined.

    Further in time, i decide to it again the menu item "Show about Panel"

    Let's see what happens in showAboutPanel:sender method:
    I test again my outlet ,
    but this time aboutPanel is no more nil, it's value is the address of the About Panel(which still existing in memory), so (!aboutPanel) = NO; so then i go to the else statement and i unhide my About Panel, and put it in front :
    I close again my About Panel, it will not release my Panel, and my outlet will point again on the well defined piece of memory occupied by the About Panel. And So on, And so on.

    Let me correct your piece of code, will you.
    In your if statement,
    Calling [aboutPanel makeKeyAndOrderFront:self]; is redundant, because when you load your nib, instances are created and when our about panel is created, its default behavior is to be on front of our app (it's acting like a basic panel).

    Anyway, i hardly recommand you to try my piece of code. It works on my mini-mac mac os x 10.5.8.
    Your piece of code is valid, but i say that it is not well optimized according me.

    Sincerely, me.
     
  14. macrumors newbie

    Joined:
    Jan 13, 2011
    Location:
    Houston
    #14
    Question about BOOL success

    Is the point of using BOOL success = .....

    only so that you can test if you successfully loaded the nib file?

    As is, my code:

    Code:
    if (!aboutPanel) {
    [NSBundle loadNibNamed:@"About" owner:self];
    }
    else {
    [aboutPanel makeKeyAndOrderFront:self];
    }
    
    With File's Owner as my AppController (not a window Controller), and aboutPanel an outlet to my panel titled "About."

    Also - according to Apple Documentation, an NSPanel's default behavior is to NOT release when sent the message [panel close] - this is however not consistent with the "Release on close" checkbox being on by default in Interface Builder. Odd?
     

Share This Page