Re: Multiple NSWindowcontroller for the same NSDocument
Re: Multiple NSWindowcontroller for the same NSDocument
- Subject: Re: Multiple NSWindowcontroller for the same NSDocument
- From: Thomas Lachand-Robert <email@hidden>
- Date: Tue, 18 Dec 2001 22:48:33 +0100
Le mardi 18 dicembre 2001, ` 07:35 , Andrea Perego a icrit :
Hi!
In my document-based project, a window displays a single part of a
document
(a spectrum, while the document consists of an array of spectra).
Therefore,
I'd like to allow the user to have more than a window open for the same
document, so that different spectra are displayed at the same time.
That's exactly the purpose of Window controllers.
I fear I miss something in the complex relationship among Document <->
WindowController <-> nib file <-> window, but, up to now, re-reading the
docs
was of no use to me. If someone of you can see immediately the mistake I'
m doing, I'll be glad to stand corrected.
This is quite flexible, but in your case, you should probably have:
-- 1 document for each 'model document' (corresponding to a file, etc.).
You subclass NSDocument for that, and you don't need to worry with the UI
in that class.
-- as many windows as the user requests;
-- 1 window controller for each window. They have to be of different
classes if the windows are different (not the same number of buttons for
instance). The rule of the controller is to manage all the UI items like
buttons, etc., and to send appropriate messages to the document and other
model objects, corresponding to user actions.
-- 1 nib file for each different class of window controller; put here the
window itself, and declare your window controller's class here as the
'file owner'.
Now here are the connections, they are automatically created for you by
Cocoa:
-- the owner of the nib file (your controller) has an 'outlet' (==
instance variable) named 'window', you just have to connect it to the real
window in the nib. So the controller knows the corresponding window;
-- the window usually don't need to know its controller, but it's
frequently the same as its delegate (don't forget to make the
corresponding connection in IB);
-- each NSWindowController (and subclass) knows about its 'document' with
[self document];
-- each document has a list of controllers. If you need a new controller,
you have to add it to this list (see below).
Here is an example exerpt from the commandant project (feel free to look
at the whole thing at
http://lachand.free.fr). My document class uses one
text window (=> 1 CmdTextWindowController, created with the document), and
possibly many graphics windows (=> n CmdGraphicsWindowController). These
are created on user request, from a menu action:
/** Create a new graphic windows for this document. */
-(IBAction) openNewGraphicsWindows:(id)sender {
[self createNewGraphicsWindow:0];
}
Note that it works because the document has been put in the responder
chain i this project. I could as well have used the
CmdTextWindowController, replacing 'self' by [self document]. The
application delegate would not be correct here, since this action is
targeted to a particular document.
The createNewGraphicsWindow is implemented as follows:
/** Create a new graphic window, and return the corresponding
CmdGraphicsWindowController.
If order == 1 is set, the new window comes in front of others (even text
ones);
if order == 0, it comes after the document window, but before the current
graphics window;
if order == -1, it comes after the current graphics window. */
-(CmdGraphicsWindowController*) createNewGraphicsWindow: (int)order {
CmdGraphicsWindowController *controller;
int orderMode;
NSWindow *keyWindow, *window; // the window it should be next
if (order != 1) keyWindow = [[NSApplication sharedApplication]
keyWindow];
if (order == -1) window = [[self graphicsWindowController] window];
else window = [[self textWindowController] window];
controller = [[CmdGraphicsWindowController alloc] initWithTag:
++graphicsTag];
if (!controller) return nil;
[self addWindowController: controller];
if (order == 1) orderMode = NSWindowAbove;
else orderMode = NSWindowBelow;
[[controller window] orderWindow: orderMode relativeTo: [window
windowNumber]];
if (order != 1 && keyWindow) [keyWindow makeKeyWindow];
[controller release];
// other initialisations specific to this project
return controller;
}
The key point is [self addWindowController: controller]: this method
(inherited from NSDocument) registers the controller in the list. It also
retains the controller, hence the [controller release] later, and lets the
controller know about its document. Now the [[controller window]
orderWindow:...] will actually place the window as expected.
Finally here is the init method for the graphics controller (I use a tag
to distinguish between the different graphics window):
-(id) initWithTag: (int)theTag {
self = [super initWithWindowNibName: @"CmdGraphics"];
tag = theTag;
[self setShouldCascadeWindows:NO];
[self setShouldCloseDocument: NO];
// other initialisations specific to this project
return self;
}
Hope this helps,
Thomas Lachand-Robert
********************** email@hidden
<< Et le chemin est long du projet ` la chose. >> Molihre, Tartuffe.