I have a Cocoa application built using Garbage Collection with a main window. This window provides a button which triggers an action on the window’s controller when it is clicked as follows:
- (IBAction) buttonClick:(id)sender {
utilityWindowController = [[UtilityWindowController alloc] initWithWindowNibName:@"Utility"];
[utilityWindowController showWindow:sender];
}
This works fine, except that every time the button is clicked, a new window is opened, even if the one I got last click is still displayed. Ok – that’s what I’ve asked it to do, but I want only one instance of this window at a time. So the behaviour I want is:
- if the window is not displayed, create a new one and show it.
- if the window is being shown, either do nothing, or maybe focus the existing window (bring to front etc).
To try to get this behaviour, I tried this:
- (IBAction) buttonClick:(id)sender {
if (!utilityWindowController) {
utilityWindowController = [[UtilityWindowController alloc] initWithWindowNibName:@"Utility"];
}
[utilityWindowController showWindow:sender];
}
So that works better, because now my main window remembers the controller I created the first time I clicked the button and just shows the window if it already has one. However, it is basically reusing the same window, which causes another problem.
The utility window has a graphical display and starts a timer when it is first created. The utility window controller has a windowWillClose: method that disables the timer when the window is closed, since it’s not useful to continue have the timer fire when the user can’t see the display. However, when the user clicks the button in the main window to display the utility window for a second time, the window shows just fine, but the timer is not started again.
I cannot seem to find something like a windowWillShow: method that I could use to restart the timer.
The other way would be if the code above would be able to detect that the utility window was closed and recreate a new one so the awakeFromNib method would get called to start the timer. However, I don’t know how I can do that.
A third method would of course be to proceed with the second version of the code above, but call a separate method that I will provide in the utility window controller that will start the timer if not already running.
What would be the best method of handling this type of thing? It seems like a fairly standard window management thing, but I haven’t quite worked out the correct way of doing this in Cocoa.
There isn’t a delegate method or notification when a window is ordered in.
I would give the window controller another method that shows the window (if it isn’t already up) and starts the timer (if it isn’t already running), and have
buttonClick:simply send that message to the window controller.The other way would be to use the original code, disable the button after creating the window controller, and re-enable the button (and destroy the window controller) when the window is closed. The disadvantage of this is that it leaves the user with no easy way to get back to the second window from the first (e.g., if they have a lot of windows on screen). If you leave the button enabled, you can have it order the window front again even if it’s already up. That’s why I’d go with my suggestion above.