Link to home
Start Free TrialLog in
Avatar of HappyCactus
HappyCactusFlag for Italy

asked on

Opening a new Window from a nib

I am trying to opening a window and assigning a controller with some data in it, without success.
I attach a brief source code.

The application is simply a main window with a button that opens a secondary window with a button. The secondary window has a controlling object called "ActionPanel".
The main window's button is connected to the ShowPanel action. It create the ActionPanel controller, initialize with the nib and prints for debug the "self" variable - that's what DebugMe does.
The second windows has a button connected to the same DebugMe method.
The application works as expected, but the ActionPanel object that receive the actions from the NIB is not the one I created.
The thing I am not able to understand is why the ActionPanel object changes between the ShowPanel instance and the one effectively connected with the nib.
This is the output I have in debug:

2010-04-23 11:26:59.032 Panels[4145:a0f] debug: I am <ActionPanel: 0x100212fe0>, target is <PanelsAppDelegate: 0x100137b80>
2010-04-23 11:26:59.856 Panels[4145:a0f] debug: I am <ActionPanel: 0x100165aa0>, target is (null)

The first line is the output of DebugMe called from the ShowPanel method, the second is print when I click on the second window's button.
I am sure I am missing something very trivial concept, can someone explain? Thank you in advance.
@implementation PanelsAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{
}

- (IBAction) ShowPanel : (id) sender
{
	ActionPanel *panel = [ [ ActionPanel alloc ] initWithWindowNibName: @"ActionPanel" owner: self ];
	[panel retain];
	[panel setTarget:self];
	[panel DebugMe:self];
	[panel showWindow:self];
}

Open in new window

Avatar of jacekmalinowski
jacekmalinowski
Flag of Poland image

First of all iPhone application can has only one window. You can have many UIViews and UIViewControllers. As I understand ActionPanel inherits from UIViewController? If it is so you should display it liker this:
[window addSubview: panel.view];

To change between views you can just do:
[window exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
Avatar of HappyCactus

ASKER

Thank you for your response, but I forgot to mention that I am developing under MacOSX Snow Leopard, not under iPhone OS. XCode version is the latest (3.2.x?).

Thank you again.
Ahh ok.

You can try changing init method of ActionPanel so inside init you read NIB file. Example: in my case MainMenu inhetrits fom UIView and MainMenu NIB has only UIView class.
-(MainMenu*) initWithFrame:(CGRect)frame
{
	if (self = [super initWithFrame:frame]) {
		NSLog(@"MainMenu init");
		//load the uitest.xib file here.  this will instantiate the 'subview' uiview.
		[[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:self options:nil];
		//add subview as... a subview.  This will let everything from the nib file show up on screen.
		[self addSubview:subview];
	}
	return self;
}

Open in new window

MainMenuNIB.png
I tried your solution, but AppKit is slight different, so I had to make some modifications.
loadNibNamed is static in AppKit, so the syntax is different.
Also, if I call +loadNibNamed from inside -init, with self as owner, the programs loop since loadNibNamed calls init for the owner, and the program hangs. If I call it with nil as owner, it do not work.
The only way to make it work is to call loadNibNamed from outside the object, but in this case it works exactly as the original version.

Let's try to change the problem slightly.
I have to open a window with a controller that must know his owner (his delegate object) to call a method. I want to update some data owned by the main window from the secondary window.
I think it should be a very trivial and common problem... Where am i wrong?
I read twice all comments and it fully confused me. In the beginning, the question was about a view switching and a problem with the panel. Now we are talking about a design problem. Right?
I do not understand the problem, so my comment is a very general and you can simply ignore it.
I'd recommend you to follow the MVC - new view will update a data in the controller (C) and all views (V) should be updated accordingly.
Maybe this tutorial will be interesting for you:
http://devinsheaven.com/cocoa-tutorial-passing-messages-between-objects-notifications-delegates-and-target-action/
And here, I hope, you will find the solution:
http://juliuspaintings.co.uk/cgi-bin/paint_css/animatedPaint/019-NSControl-NSView.pl
pgnatyuk,

I changed approach to the problem, since I cannot solve an apparently simple issue directly.
The original problem borns on a very specific application I am designing.
I must tell that I am totally new on ObjC and Cocoa. I am reading "Cocoa Programming - Developer's handbook" by David Chisnall, an indeed good book but a bit obscure for the primer. I have - I think - a great experience in OOP, I develop in C++ since '93, and have experience in developing in general.
I usually develop for Windows with QT and MFC.
I understand that Cocoa have a completely different approach in applications.
So then, I am developing a little tool to keep some data in a database - a license management tool for my own use, so I can experiment and learn Cocoa.
The approach I was using is: a main window that reports a table view with all the license data, a set of pushbutton to add, remove and edit each record.
The problem was with the "add" button, that opens a new panel or window that adds a record into the database and generate a new license file when an "add" button is clicked.
I faced the problem because i was thinking to pass the delegate or another object to the panel and used the code above. So I simplified the program to isolate the problem.
So there are two order of problem:

1) find a correct architecture or approach to this kind of application, and
2) understand why the original approach do not work.

moreover, a third problem could be

3) how usually one open a new panel or window and pass / feed some data in it?

(this is a subproblem of 1).
thank you for your responses.

(I doubled the point value)
I have this book too. I read only few pages from the beginning. I think I will like this book too.
"Cocoa programming for Mac OS X". Aaron Hillegass. I use this book for the learning. It is really great - very simple, not boring, etc.
I work with Objective-C only few months. My experience with Cocoa is very short - few very standard applications. It is a change for me - a parallel with my Windows programming - I did make a lot of MFC applications, but the real commercial projects were written without MFC, only non-standard GUI makes the Windows application really nice. On Mac the standard GUI looks different and behaves different, and even big commercial projects use the standard Cocoa framework.

1) You know, Cocoa dictates you which architecture you have to use - MVC.
2) I think, you can use your original approach too.
3) always. In any application. For example Mail, iCal, ...., each application actually.
 
So you want to make this panel to work with your views? You have few buttons in a panel and few custom views and switch them?
Hillegass book is in my wish list! Amazon, eh? ;-)

1) I supposed that, since it is a side effects of highly structured frameworks. Also MFC tends to dictates the paradigm of application developing, but MFC are much less structured and so you can also try other architectures - and this is the worst aspect of MFC!

2) ok. So where I am wrong?

3) I think I didn't well understand this response, can you explain?

I didn't make use of custom views - only one table that reports the license number, and a window to insert data.
But now, concentrate our attention on the original problem, since, as you say in 2), we can use the original approach to solve this issue.

I have a main window with a button.
This button opens a new window or panel with a button. This other buttons only NSLog() the value of self - like the output I posted earlier.
How can this be accomplished?
What's wrong with my original code?
and why the "panel" variable value I wrote after creating and opening the panel is different from that one I see when I push the second button?

ASKER CERTIFIED SOLUTION
Avatar of pgnatyuk
pgnatyuk
Flag of Israel image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ok pgnatyuk, thank you for your suggestions.
I'll study this solution.
Only one question remains open, why my approach do not work.
If i call this method:

- (IBAction) ShowPanel : (id) sender
{
      ActionPanel *panel = [ [ ActionPanel alloc ] initWithWindowNibName: @"ActionPanel" owner: self ];
      [panel retain];
      [panel setTarget:self];
      [panel DebugMe:self];
      [panel showWindow:self];
}

Why the DebugMe call in this code snipped outputs a different value for self than the case when DebugMe is called from the click event of the ActionPanel Button.
DebugMe simply is

NSLog (@"debug: %@", self);

I imagine that if I can understand why this code is wrong, I understand why my approach and my architecture cannot work.
Do you have any idea?
That's the point I didn't understand in your original question too.
Where is (in which class) you have this code?

[panel DebugMe:self];
What does it mean? That you send a message DebugMe with parameter self to the panel instance. So how this DebugMe looks like? Maybe you wanted something like:
[self DebugMe];
Oh you're right ;-)
DebugMe is used as an action, so is defined as

 -(IBAction) DebugMe : (id) sender;

I attach you the complete project. Forget about the DebuggerWindowController class, it was just a test.
The output I have is
2010-04-24 12:42:43.162 Panels[7931:a0f] debug: I am , target is
2010-04-24 12:42:43.183 Panels[7931:a0f] Action Panel Initializing.
2010-04-24 12:42:45.624 Panels[7931:a0f] debug: I am , target is (null)

The third line is the output when I click the button on the ActionPanel. I would expect the same content as the first line. This is what I do not understand. So I cannot set "target" as I want.

Attached the project.

Thank you

 
uhm, I have a problem with the upload... .ds_store file is not allowed... I'll upload the file somewhere or sent you privately, if you need it.
Let's try to fix everything remotely. Today is a weekend and it is nice to talk here, read books about Cocoa, try something in Xcode. But if I will download your project... it will be a working day already, like a usual day in the office.
I think, I do understand the requirements well. You have an application - Document-based or you simply created a Cocoa project with one window and the main menu? Then you put TableView on it.
You want to adde one more window that will look as a new window with few NSTextFileds and buttons where you will edit a record from the table view. Right?

Thank you pgnatyuk!
I do not mean to disturb you in the week end. Feel free to answer when you have the time.

My application was built from scratch, selecting a Cocoa Application with CoreData, but it is not Document Base (IIRC).
It haves a main window and a menu (of course).
The main Window have a table that reports some field of the database (license number, customer name, creation date).
From this window you can: Create New Records, Remote the selected record or edit it.
When you create or edit the record, a secondary window will open (a panel). There you have many NSTextFields and other controls. One button is "Add" and it create a new records with some data (not displayed by the table). Also it creates a license file by accessing a C++ library linked with.
BTW, there is also a list box that I can fill with many License number, and batch create both records and license file. With it I can create many files at once.

Hope all is clear, if in doubt, ask me please.

Thank you for your patience.
Yes. It's clear and pretty standard GUI design. Everything will work fine.
It was not very difficult to change views in one window. I have two views in two different xib-files. I show them in one box in one window. I do resize the window accordingly to the view size. The program has two separate view controllers. The box allows me a simple view switch:

[box setContentView:currentView];

It's Core Data Document-based application.
Actually, it's all taken from the "Cocoa Programming For Mac OS".

I found a project with a similar name:
http://developer.apple.com/mac/library/samplecode/DepartmentAndEmployees/Introduction/Intro.html

Take a look. I hope it will help you a lot.

I recovered a previous version of this application.
In this application there was a different approach: the panel was shown from start of the application, and it was created in a different way - it was put inside the same xib file.
And it worked correctly.
I'll try to see if the approach can be modified a bit. If it do not work (as you remarked, the design is clean and it should work), I'll try the "multiple view" approach.
Again, I do not understand why it do not work, I'll be grate if someone could explain why.
Maybe it didn't work because of a mistake made when you worked with Interface Builder - I do such mistakes always.
This way will work, it is simplier.
I have an app where 2 different views are in two different nib-files, but I show them in the same window. The algorithm is, maybe, simple: create separate view controllers, load the nibs by name and show the view. But it will be difficult to explain with more details. If you will need, I will look for a tutorial in the internet.
 
 
Hi pgnatyuk,

thank for your responses, I have decided to change approach to my application, it will be a document-based application with core data support. Is is much simpler indeed, I have already started the project but I have some problem to solve.. not related with the current issue.
So I'll accept your suggestion as a solution.

Regards and thanks again.
thank you for your assistance.