Chapter 12 Challenge


#1

I tried to complete the challenge of creating a custom About Panel.

So far I have been able to create a panel in much the same way as the chapter 12 method of creating a preference panel but it does not follow the directions of the challenge.

I created a NSWindowController class called AboutController, Made an About.xib file and made all of the connections to get a working custom about panel in the program.

I am left not knowing if I should have created the AboutController or should I have handled this process in some other way that was not demonstrated in the chapter.

The challenge states to use NSBundle. Do I use the NSBundle in my AboutController class or should it be intended in some other section of code. Should I even have an AboutController class. I see near the bottom of page 205 a line BOOL successful = [NSBundle loadNibNamed:@“About” owner:someObject]

Not clear where I could use that line… Which code section… is the someObject referenced above ‘AppController’

I see the Challenges as very benificial if there is a way to check my result against the target of the challenge, but I feel lost and not sure I am going in the right direction.

I have already skipped the Chapter 11 challenge because I didn’t know where to put the code , I don’t want to skip this challenge for the same reasons. I feel I am on the verge of grasping this stuff just wish I had several more examples with full instructions.


#2

The exercise in Chapter 12 walks you through creating a new window using an NSWindowController subclass. This is the way that you will want to create most new windows in your application. An About panel, however, is usually so simple that it doesn’t need a dedicated NSWindowController. You can have the AppController object serve that purpose. The goal of the challenge, then, is to use NSBundle to do it the ‘lean and mean’ way.

So, yes, you will want to us +[NSBundle loadNibNamed:owner:], and yes the owner is your instance of AppController. So you’re already headed in mostly the right direction. Here’s a hint: put the call to +loadNibNamed:owner: in an action method of your AppController, showAboutPanel:.

You don’t need an AboutController for this challenge, but as I mentioned above in a real program that would certainly be the usual path to take.

Let us know if you need any other hints. This is an important concept to be comfortable with, and you’re putting together a number of key components of Cocoa: actions, outlets, NIBs, File’s Owner, etc.

Adam


#3

I wanted to keep my working about panel that uses a class and add a second about panel that follows the challenge.
To do this I added a new menu item called About Raiseman2.

I linked About Raiseman2 to the new action I created in the AppController
and added the +[NSBundle loadNibNamed:owner:] to that action .

I have both versions displaying but I have some questions about how they should appear. Neither of my about windows are modal, should they be? I can click on other windows of the app without first closing the about window.

On the NSBundle created about window I can return to the About Raisman2 window and create multiple instances of the About Raisman 2 panel.
Only one instance is possible on the about window that I created with aboutController class.


#4

Correct, these windows are not modal. (You can create a modal window with NSApplication’s -runModalForWindow:.)

With your AboutController window, you should be able to create multiple windows, but you will need to create a new instance of your window controller class for each window you want to create.

Adam


#5

I have another Question to the Challenge.

i made the challenge as told in the book by using NSBundle. Everything works fine as it should. But i found a difference between my project an the solution and i can’t still figure out how to get it like in the solution. In AppController.h i added the outlet “aboutPanel” like in the solution. But with control-click on the File’s Owner of the About.xib there is no aboutPanel to connect to the panel itself. I don’t know why. But the aboutPanel is working fine. it comes up when i click on “about”.

Sorry for my english. I am working on it!

Tobias


#6

Hi Tobias,

I think you forget to set AppController as File’s Owner for About.xib (–> Identity Inspector --> Custom Class)

cu
Vertex


#7

Hi Vertex,

great work! That was it! Next time i will hopefully remember this step!

Thank you.

Tobias


#8

I came up with a quick fix to check to see if an about window is already open when using the NSBundle method:

- (IBAction)showAbout:(id)sender { NSArray *windows = [[NSApplication sharedApplication] windows]; for (NSWindow *window in windows) { if ([[window title] isEqualToString:@"About"]) { return; } } [NSBundle loadNibNamed:@"About" owner:self]; }

The title was the only thing that immediately popped out for me to search for, but this does prevent multiple about windows from opening and you don’t have to create a separate controller for it.

[strike]It would be handy if the loadNibNamed:owner call actually returned an NSBundle or NSWindow object we could keep track of instead of just a boolean, but no :frowning:[/strike]

Silly me, didn’t see the part about creating an outlet in AppController. No need for the workaround when you can just check to see if the outlet is nil or not :confused:


#9

My solution was pretty simple. Just make the NIB and settings as the text said.

Then I did this code:

[code]- (IBAction)showAboutPanel:(id)sender
{
// Test to see if one is already open
if (!AboutPanel) {

    // Load the Nib by name
    [NSBundle loadNibNamed:@"AboutPanel" owner:self];
   
}

}[/code]

and I was done.

I did get a bit off track at first going down the road of something like this:

and then trying to get myBundle to load the nib. I got that to work, but the method is different and I couldn’t get it to only show one instance of the panel.


#10

I’ve got the About panel working fine. I can bring it up and dismiss it. And you can only get one instance of the About panel to show up at once. The problem I’ve run into is this:

  • open the About panel
  • close it
  • open the About panel again
  • now I can’t close it. The close button looks as though it’s moused over (the X is visible) and there’s no way to close the panel

Here is the code I use to open the About panel:

-(IBAction)showAboutPanel:(id)sender
{
	if (!aboutPanel)
	{
		NSLog(@"There is no aboutPanel yet");
		[NSBundle loadNibNamed:@"About" owner:self];
	}
	NSLog(@"Showing %@", aboutPanel);
	[aboutPanel makeKeyAndOrderFront:nil];
}

Any idea why the panel gets stuck open when I open it the second time?

Thanks a lot,
Erik


#11

Erik,

I haven’t seen that one before. Is there an exception in the console (debugger area) when you click the close button?

Adam


#12

Nothing that shouldn’t be there. This is the output when opening once, closing, then opening the second time. None of the buttons on the About panel are functional. The close and maximize buttons are locked in their “hover” state. And ESC won’t close the panel either.

2012-02-17 08:45:18.684 RaiseMan[61197:403] There is no aboutPanel yet
2012-02-17 08:45:18.687 RaiseMan[61197:403] Showing <NSPanel: 0x7facd24c25a0>
2012-02-17 08:45:29.306 RaiseMan[61197:403] Showing <NSPanel: 0x7facd24c25a0>

#13

Adam,

It seems the problem is that I had the NSPanel’s “Release When Closed” prop checked in IB. That seems to the be the default setting. I’m not entirely sure why that would result in the problem I was having, though.

Erik


#14

I came up with a solution similar to one in a previous post, except that I used the isVisible property. (I also have “Release When Closed” checked.)

- (IBAction)showAboutPanel:(id)sender
{
    if (![aboutPanel isVisible]) {
    // load NIB
    }
    // Make it the key window
}

This seems to work perfectly, but I’m concerned that each time I load the NIB, I’m actually creating a new instance of the aboutPanel. Is there any way to not only release but also deallocate the NIB?


#15

Thanks for explaining that. It wasn’t clear to me when and why we should use NSBundle to load a NIB file instead of NSWindowController from the discussion about NSBundle in the chapter.