我有一个应用程序可以使用以下命令针对不同的视图调整大小:
NSSize currentSize = [[box contentView] frame].size;
NSSize newSize = [v frame].size;
float deltaWidth = newSize.width - currentSize.width;
float deltaHeight = newSize.height - currentSize.height;
NSRect windowFrame = [w frame];
windowFrame.size.height += deltaHeight;
windowFrame.origin.y -= deltaHeight;
windowFrame.size.width += deltaWidth;
[box setContentView: nil];
[w setFrame: windowFrame
display: YES
animate: YES];
[box setContentView: v];
更改视图时,窗口会根据应用程序的左上角增大/缩小。无论用户退出时处于哪个视图,该应用程序始终从第一个视图启动,因为这是一个摘要视图。我也希望它可以恢复,以便在启动时打开最后使用的文档。
问题是:由于大多数视图都比摘要视图高,因此将其更改为一个视图会将窗口的左下角推到屏幕下方。现在退出该应用程序并重新启动,然后该应用程序将窗口定位到先前左下角的位置。我知道这是因为这是Cocoa放置原点的地方,但是对于用户来说,让窗口在相同的左上角重新启动更加有意义,否则,每次打开应用程序时,屏幕都会向下移动。
我尝试观察NSWindowWillCloseNotification并再次调用上述方法,以在关闭之前将应用程序重置为摘要视图,但是即使代码工作正常,窗口仍会在错误的位置启动-我猜可可在设置应用程序可恢复的默认值之前通知已发送。
之前已经完成:系统偏好设置-它会自动调整视图的大小,指示您的初始视图是什么,但是您可以移动窗口,下次打开它时,它将位于左上方的新位置角。有人知道如何模仿吗?
编辑:Document.xib有一个带有弹出按钮和一个框的小窗口。下面的方法更改视图并调整窗口大小以适合这些视图。在应用程序打开时,一切工作正常,仅当应用程序关闭并用活动文档重新打开时(例如,使用Lion的还原),窗口移动才是问题。
============================ | Jump to:___ | The "===" is the top and bottom edge of the window | | The "___" is the pop-up menu for selecting the view | -------------------------- | The dashed box on the inside is "box", which holds the views || || || || || || || || || || || || | -------------------------- | ============================
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
[super windowControllerDidLoadNib:aController];
//Note that init creates the array viewControllers
NSMenu *menu = [viewMenu menu];
NSUInteger i, itemCount;
itemCount = [viewControllers count];
for (i = 0; i < itemCount; i++) {
NSViewController *vc = [viewControllers objectAtIndex:i];
NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: [vc title] action: @selector(changeViewController:) keyEquivalent:@""];
[mi setTag: i];
[menu addItem: mi];
}
[self displayViewController: [viewControllers objectAtIndex: 0]];
[viewMenu selectItemAtIndex: 0];
}
- (void) displayViewController: (ManagingViewController *) vc {
//End editing
NSWindow *w = [box window];
BOOL ended = [w makeFirstResponder:w];
if (!ended) {
NSBeep();
return;
}
//Put view in box
NSView *v = [vc view];
NSSize currentSize = [[box contentView] frame].size;
NSSize newSize = [v frame].size;
float deltaWidth = newSize.width - currentSize.width;
float deltaHeight = newSize.height - currentSize.height;
NSRect windowFrame = [w frame];
windowFrame.size.height += deltaHeight;
windowFrame.origin.y -= deltaHeight;
windowFrame.size.width += deltaWidth;
[box setContentView: nil];
[w setFrame: windowFrame display: YES animate: YES];
[box setContentView: v];
}
- (IBAction)changeViewController:(id)sender {
NSUInteger i = [sender tag];
ManagingViewController *vc = [viewControllers objectAtIndex: i];
[self displayViewController: vc];
}
我尝试将来自@trudyscousin的建议代码的第一块放在
-windowControllerDidLoadNib:
中的for循环下面,并且正确锚定了窗口,但是当代码到达-displayViewController:
时,它将设置currentSize =(6,6)。我不确定这是否是因为IB中的框为空。然后,它将(6,6)与SummaryView的大小之差添加到应用程序上一次退出时的窗口大小,使其变得巨大。然后,我尝试通过在
-changeViewController:
中添加两行来使用NSUserDefaultsNSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setInteger: i forKey: @"lastViewController"];
并在
-windowControllerDidLoadNib:
中NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if ([userDefaults integerForKey: @"lastViewController"]) {
NSInteger i = [userDefaults integerForKey: @"lastViewController"];
ManagingViewController *vc = [viewControllers objectAtIndex: i];
NSView *v = [vc view];
NSSize currentSize = [v frame].size;
[box setFrameSize: currentSize];
[self displayViewController: vc];
[viewMenu selectItemAtIndex: i];
} else {
[self displayViewController: [viewControllers objectAtIndex: 0]];
[viewMenu selectItemAtIndex: 0];
}
这是可行的,但是会强制应用程序使用上一次使用的视图启动,这不会太糟,除了在打开/创建新文档时甚至可以做到这一点。如果我取消了其他操作(即始终运行最后两行),那么我将回到开始的位置-该应用的启动将在屏幕上垂直向下移动。看来您无法在启动时设置窗口的原点,或者可能稍后会重新加载其默认值。
我做的最后一件事是回到起始代码(不使用@trudyscousin提供的掩码代码),但在
-windowControllerDidLoadNib:
的底部添加了:[self performSelector: @selector(adjustOrigin) withObject: nil afterDelay:0.0f];
哪个调用:
- (void) adjustOrigin {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if ([userDefaults integerForKey: @"lastViewController"]) {
NSInteger i = [userDefaults integerForKey: @"lastViewController"];
ManagingViewController *vc = [viewControllers objectAtIndex: i];
NSView *v = [vc view];
NSSize previousSize = [v frame].size;
NSSize currentSize = [[[viewControllers objectAtIndex: 0] view] frame].size;
CGFloat delta = previousSize.height - currentSize.height;
NSRect windowFrame = [[box window] frame];
windowFrame.origin.y += delta;
[[box window] setFrame: windowFrame display:YES];
}
}
这实际上是可行的,但是如果有多个事情在运行,则滞后就足以使您看到窗口使“跳转”到其新起点,这有点不雅观。
最佳答案
您的代码似乎是正确的,但真正的问题可能是您的文档xib。
如果将文档xib设置为自动版式,则将其关闭。您可以通过选择Xcode中的文件来实现。在文件检查器中,关闭“使用自动版式”复选框。
完成此操作后,选择弹出按钮。在大小检查器中,将按钮固定在顶部和左侧。选择您的框。在尺寸检查器中,将框固定在所有四个侧面上,并确保其水平和垂直扩展。
回顾一下我先前的答案,这是您的-windowControllerDidLoadNib:方法,其中包含我之前建议的更改:
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
[super windowControllerDidLoadNib:aController];
//Note that init creates the array viewControllers
NSMenu *menu = [viewMenu menu];
NSUInteger i, itemCount;
itemCount = [viewControllers count];
for (i = 0; i < itemCount; i++) {
NSViewController *vc = [viewControllers objectAtIndex:i];
NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: [vc title] action: @selector(changeViewController:) keyEquivalent:@""];
[mi setTag: i];
[menu addItem: mi];
}
// ---
NSWindow *myWindow = [[[self windowControllers] objectAtIndex:0] window];
NSUInteger styleMask = [myWindow styleMask];
styleMask ^= NSResizableWindowMask;
[myWindow setStyleMask:styleMask];
if ([myWindow setFrameUsingName:@"windowFrameAutosaveName"] == NO)
{
[myWindow center];
}
(void) [myWindow setFrameAutosaveName:@"windowFrameAutosaveName"];
styleMask &= ~NSResizableWindowMask;
[myWindow setStyleMask:styleMask];
// ---
[self displayViewController:[viewControllers objectAtIndex:0]];
[viewMenu selectItemAtIndex:0];
}
我删除了较旧的注释,但现在指示其他代码在哪里。这样,您不必费心维护自己的文档默认值,也不必费心调整原点。
将这两件事放在一起,就可以(大体上)解决问题。
是的,我需要对此进行一些限定。您的应用程序是基于文档的应用程序,因此您将不得不想出一个唯一的名称以在用户默认设置中保存文档的窗口位置,或者以某种方式将该信息与文档一起存储本身。
一如既往,祝您工作顺利。