views:

390

answers:

6

Hello everyone,

I have a weird problem with positioning a window on screen. I want to center the window on the screen, but i don't know how to do that. Here's what i've got. The window is created from nib by the main controller:

IdentFormController *ftf = [[IdentFormController alloc] initWithWindowNibName:@"IdentForm"];
[[ftf window] makeKeyAndOrderFront:self];

Now the IdentFormController has awakeFromNib() method in which it tries to position the window. For the sake of simplicity i've just tried to do setFrameOrigin(NSMakePoint(0, 0)). What happens is as follows:

The first time i create this window, everything works as expected. But if i create it again after releasing the previous, it starts appearing at random positions. Why does it do that?

A: 

This isn't a duplicate, but you may want to have a look at the answers to this question: http://stackoverflow.com/questions/1855034/centering-windows-on-screen

Abizern
Actually, this has the same problems as i did. I've added [self release] to the window's close handler and the problem disappeared. Before that the controller wasn't being freed. But there shouldn't be a problem like that anyway since every controller is a different instance ... Well, weird ... At least it works now.
Marius
By the way, you can use `[window center]` to position a window in the visual center of the screen.
Rob Keniger
Unfortunately, visual center is the apple way and i hate it. It's not what i want :)
Marius
If you don't like NSWindow's center method you can always override it: - (void)center { NSRect windowFrame = [window frame]; NSRect screenFrame = [[NSScreen mainScreen] frame]; screenFrame.origin.x += NSMidX(screenFrame) - NSMidX(windowFrame); screenFrame.origin.y += NSMidY(screenFrame) - NSMidY(windowFrame); [window setFrameOrigin:screenFrame.origin]; } // - (void)centerNote that the default center accounts for the dock; the code above doesn't.
geowar
If you don't like NSWindow's center method you can always override it:<br/><br/><pre><code>- (void)center{ NSRect windowFrame = [window frame]; NSRect screenFrame = [[NSScreen mainScreen] frame]; screenFrame.origin.x += NSMidX(screenFrame) - NSMidX(windowFrame); screenFrame.origin.y += NSMidY(screenFrame) - NSMidY(windowFrame); [window setFrameOrigin:screenFrame.origin];} // - (void)center</code></pre>Note that the default center accounts for the dock; the code above doesn't.
geowar
(SORRY, STUPID <CODE></CODE> TAGS DON'T WORK…)
geowar
A: 

First of all, it sounds like you need to check "dealloc on close" or "release on close" in the NSWindow's property inspector. Then the window will clean up after itself and you can remove the (risky) call to [self release] in your own code.

awakeFromNib is called after all objects from the nib have been unarchived and outlets have been connected, but that may be too early to be setting the window coordinates. I believe Cocoa does some work to automatically position subsequent windows below and to the right of existing windows, so that new windows don't completely obscure old ones. It is likely doing this AFTER you set the position in awakeFromNib, stomping on your changes.

The best place to set your window position is probably in one of the NSWindow delegate methods (windowWillBecomeVisible: perhaps), or possibly right before you call makeKeyAndOrderFront:.

benzado
For some reason it didn't work when the release on close was checked. The window might have been deallocating and cleaning up, but how about the controller? Maybe it wasn't being deallocated. As soon as i've added [self release] - the thing finally worked. Maybe it's risky, but at least it works and when you release a controller - then it cleans up the window as well.
Marius
I think I misinterpreted `[self release]` as applying to the NSWindow instance, not the controller. Maybe to make things clearer, your app delegate should maintain a pointer to the current IdentFormController. Or if you have to release self, use `autorelease` so the object isn't deallocated until the end of the run loop. Regardless: did moving the code to a delegate method help?
benzado
Well, i didn't have a chance to test it yet, but i'm sure it would work. If it works with [self release] - then why wouldn't it work from outside. By the way: why is [self release] risky? If i'm sure i won't need this controller and nothing's going to try and access it - what problems could occur with [self release] ?
Marius
`[self release]` is risky because you could be executing the code of an object that has been freed. If it's the last line of your method you will probably be OK most of the time, but there are no guarantees. Why risk it if you can call `autorelease` instead?
benzado
The discussion about calling `[self release]` is a distraction from your main issue: **window positioning**. Did you have any success using a delegate method like `windowWillBecomeVisible:` instead of putting the code in `awakeFromNib`?
benzado
Sorry, won't be able to test that for a while. I had success even in awakeFromNib after i made sure that the previous controller has been destroyed. Before that i couldn't set any position at all, it only worked the first time. I will just use your previous idea and modify the app to destroy the previous controller outside of itself before creating another one. Then it will also work and there won't be any releases within the controller itself. And even though everything works like a charm now, the mystery of why it didn't work before still remains.
Marius
A: 

Check out if you can set the centre of your window with the centre of your screen. And set the window position on it. It might work out.

iSight
+1  A: 

So as I understand it you want to center the window on the screen?

Well assuming NSWindow *window is your window object then there are two methods...

[window center];

This is the best way to do it but it will ofset to take into account visual weight and the Dock's presence.

If you want dead center then this would work...

// Calculate the actual center
NSPoint x = (window.screen.frame.size.width - window.size.width) / 2;
NSPoint y = (window.screen.frame.size.height - window.size.height) / 2;

// Create a rect to send to the window
NSRect newFrame = NSMakeRect(x, y, window.size.width, window.size.height);

// Send message to the window to resize/relocate
[window setFrame:newFrame display:YES animate:NO];

This code is untested but it gives you a fair idea of what you need to do to get this thing working the way you want, personally I would advise you stick with Apple's code because it has been tested and is what the user would expect to see, also from a design perspective as a designer my self I don't always rely on the actual center to be where the optical center is.

unknowndomain
A: 

You're probably running afoul of automatic window positioning. Have you tried calling

[myWindowController setShouldCascadeWindows: NO];

?

uliwitness
A: 

Would be nice if you would give credit to those who gave you your answer otherwise none who find this question on search will know what the solution was.

unknowndomain