使用Obj-C记住应用程序加载之间的Windows位置的最佳方法是什么?我正在使用Interface Builder作为接口,是否可以使用绑定来执行此操作。
推荐的方法是什么?谢谢。
答案 0 :(得分:31)
在Interface Builder中的Attributes下的Autosave字段中输入该窗口唯一的名称(例如“MainWindow”或“PrefsWindow”)。然后它会自动将其位置保存在用户默认值中。
要以编程方式设置自动保存名称,请使用-setFrameAutosaveName:
。如果您有基于文档的应用程序或在IB中设置自动保存名称没有意义的其他情况,您可能希望这样做。
答案 1 :(得分:10)
在斯威夫特:
class MainWindowController : NSWindowController {
override func windowDidLoad() {
shouldCascadeWindows = false
window?.setFrameAutosaveName("MainWindow")
super.windowDidLoad()
}
答案 2 :(得分:5)
根据doc,保存窗口的位置:
NSWindow *window = // the window in question
[[window windowController] setShouldCascadeWindows:NO]; // Tell the controller to not cascade its windows.
[window setFrameAutosaveName:[window representedFilename]]; // Specify the autosave name for the window.
答案 3 :(得分:3)
我尝试了所有解决方案。它只能保存位置,而不是大小。所以我们应该手动完成。这就是我在GifCapture应用https://github.com/onmyway133/GifCapture
上的表现class MainWindowController: NSWindowController, NSWindowDelegate {
let key = "GifCaptureFrameKey"
override func windowDidLoad() {
super.windowDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(windowWillClose(_:)), name: Notification.Name.NSWindowWillClose, object: nil)
}
override func awakeFromNib() {
super.awakeFromNib()
guard let data = UserDefaults.standard.data(forKey: key),
let frame = NSKeyedUnarchiver.unarchiveObject(with: data) as? NSRect else {
return
}
window?.setFrame(frame, display: true)
}
func windowWillClose(_ notification: Notification) {
guard let frame = window?.frame else {
return
}
let data = NSKeyedArchiver.archivedData(withRootObject: frame)
UserDefaults.standard.set(data, forKey: key)
}
}
答案 4 :(得分:2)
基于onmyway133的答案,我编写了一个RestorableWindowController
类。只要您的窗口控制器继承自它,就可以恢复窗口的位置和大小。
import Cocoa
open class RestorableWindowController: NSWindowController {
// MARK: - Public -
open override func windowDidLoad() {
super.windowDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(windowWillClose), name: NSWindow.willCloseNotification, object: nil)
if let frame = storedFrame {
window?.setFrame(frame, display: true)
}
}
open override func awakeFromNib() {
super.awakeFromNib()
if let frame = storedFrame {
window?.setFrame(frame, display: true)
}
}
open override var contentViewController: NSViewController? {
didSet {
if let frame = storedFrame {
window?.setFrame(frame, display: true)
}
}
}
// MARK: - Private -
private var storedFrameKey: String {
String(describing: type(of: self)) + "/storedFrameKey"
}
private var storedFrame: NSRect? {
guard let string = UserDefaults.standard.string(forKey: storedFrameKey) else {
return nil
}
return NSRectFromString(string)
}
@objc private func windowWillClose() {
guard let frame = window?.frame else {
return
}
UserDefaults.standard.set(NSStringFromRect(frame), forKey: storedFrameKey)
}
}
答案 5 :(得分:2)
在Swift 5.2中,在您的NSWindowController
类中:
override func windowDidLoad() {
super.windowDidLoad()
self.windowFrameAutosaveName = "SomeWindowName"
}
仅此而已!
答案 6 :(得分:0)
要恢复窗口,可以在Interface Builder中设置恢复ID。这将用作密钥的一部分,框架存储在NSUserDefaults中。 - 但那并没有(总是)为我工作。
NSWindow
有setFrameUsingName(_:)
等来配置它,就像@BadmintonCat写的那样,你也可以手动序列化窗口位置,如果不起作用的话。
我的应用中最简单的解决方案是使用NSWindowController.windowFrameAutosaveName
属性并将其设置为awakeFromNib(_:)
中的内容。该单行成功影响了加载和保存。
答案 7 :(得分:0)
对Apples AutoSave和IB BS感到厌烦,它们有时会工作,有时会不工作,并且取决于System Prefs等等的标志设置。只需执行此操作,它就可以正常工作,甚至还可以记住用户的全屏状态!
-(void)applicationDidFinishLaunching:(NSNotification *)notification
{
[_window makeKeyAndOrderFront:self];
// Because Saving App Position and Size is FUBAR
NSString *savedAppFrame = [userSettings stringForKey:AppScreenSizeAndPosition];
NSRect frame;
if(savedAppFrame) {
frame = NSRectFromString(savedAppFrame);
[_window setFrame:frame display:YES];
}
else
[_window center];
// Because saving of app size and position on screen doesn't remember full screen
if([userSettings boolForKey:AppIsFullScreen])
[_window toggleFullScreen:self];
}
-(void)windowDidEnterFullScreen:(NSNotification *)notification
{
[userSettings setBool:YES forKey:AppIsFullScreen];
}
-(BOOL)windowShouldClose:(NSWindow *)sender
{
// Have to use this to set zoom state because exit full screen state always called on close
if(sender == _window) {
[userSettings setBool:(_window.isZoomed ? YES:NO) forKey:AppIsFullScreen];
}
return YES;
}
-(void)applicationWillTerminate:(NSNotification *)aNotification
{
[userSettings setObject:NSStringFromRect(_window.frame) forKey:AppScreenSizeAndPosition];
[userSettings synchronize];
}
答案 8 :(得分:0)
对我来说,应用程序委托中的-applicationDidFinishLaunching
中的以下行可以正常工作(在Catalina,macOS 10.15下):
[self.window setFrameAutosaveName: @"NameOfMyApp"];
这一行很重要
[self.window setDelegate: self];
在setFrameAutosaveName
中的{strong>之前 -applicationDidFinishLaunching
前执行!
答案 9 :(得分:0)
像其他人一样,我发现以编程方式设置它是有效的...
self.windowFrameAutosaveName = NSWindow.FrameAutosaveName("MyWindow")
但前提是你没有在 IB 中设置它! 如果你在两者中都设置了它......你就不能工作了。
顺便说一句:我是通过在代码的末尾添加“WTF”来发现这一点的,然后突然一切正常! ?