Cocoa 中心编程创建的窗口

Cocoa 中心编程创建的窗口,cocoa,center,nswindow,Cocoa,Center,Nswindow,我一直在使用下面的示例创建一个自定义的无标题栏窗口: 我发现这是在Leopard、Snow Leopard和Lion中创建无标题窗口的唯一方法,其他方法在Leopard或Lion上都不起作用。 (如果我试图通过正常的NSWindow和IB调用一个无标题的窗口,它将不再在Leopard中启动) 到目前为止,这个自定义的无标题栏窗口在任何地方都非常有效,但我无法将其居中,只能在Interface Builder中固定一个位置 用[window center]来集中一个普通的NSWindow*窗口实

我一直在使用下面的示例创建一个自定义的无标题栏窗口:

我发现这是在Leopard、Snow Leopard和Lion中创建无标题窗口的唯一方法,其他方法在Leopard或Lion上都不起作用。 (如果我试图通过正常的NSWindow和IB调用一个无标题的窗口,它将不再在Leopard中启动)

到目前为止,这个自定义的无标题栏窗口在任何地方都非常有效,但我无法将其居中,只能在Interface Builder中固定一个位置

用[window center]来集中一个普通的NSWindow*窗口实现是相当容易的,但是我发现在这个自定义窗口子类上没有任何功能,这个窗口不是通过Interface Builder从nib创建的

我试过几次,但似乎都不管用


有什么想法吗?

问题可能是为什么
[窗口中心]
不起作用;但假设情况是这样,使用
NSScreen
获取屏幕坐标,进行数学运算,并直接将窗口居中

CGFloat xPos = NSWidth([[window screen] frame])/2 - NSWidth([window frame])/2;
CGFloat yPos = NSHeight([[window screen] frame])/2 - NSHeight([window frame])/2;
[window setFrame:NSMakeRect(xPos, yPos, NSWidth([window frame]), NSHeight([window frame])) display:YES];

这将其置于屏幕的文字中心,而不考虑dock和菜单栏占用的空间。如果您想这样做,请将
[[window screen]frame]
更改为
[[window screen]visibleFrame]
Swift版本:您可以为相同的功能编写一个简单的静态实用程序函数

static func positionWindowAtCenter(sender: NSWindow?){
        if let window = sender {
            let xPos = NSWidth((window.screen?.frame)!)/2 - NSWidth(window.frame)/2
            let yPos = NSHeight((window.screen?.frame)!)/2 - NSHeight(window.frame)/2
            let frame = NSMakeRect(xPos, yPos, NSWidth(window.frame), NSHeight(window.frame))
            window.setFrame(frame, display: true)
        }
}

我偶然发现了同样的问题。对我来说,在调用macOS Catalina 10.15.3版中的
center()
Objective-C之前,在
NSWindow
对象上将
isRestorable
设置为
false

更具可读性@Wekwa的答案

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    NSWindow * window = NSApplication.sharedApplication.windows[0];
    CGFloat xPos = NSWidth(window.screen.frame)/2 - NSWidth(window.frame)/2;
    CGFloat yPos = NSHeight(window.screen.frame)/2 - NSHeight(window.frame)/2;
    [window setFrame:NSMakeRect(xPos, yPos, NSWidth(window.frame), NSHeight(window.frame)) display:YES];
}
更新为Swift 5 我总是发现用
screen.frame
将窗口居中会使窗口感觉太靠近屏幕底部。这是因为Dock的大小几乎是状态/菜单栏的3倍(分别约为70-80px和25px)

这会使窗口看起来好像位于屏幕底部较低的位置,因为我们的眼睛不会自动调整状态栏(1x大小)和停靠(约3x大小)的插入

出于这个原因,我总是选择使用
screen.visibleFrame
,因为它确实感觉更集中
visibleFrame
同时考虑状态栏和停靠尺寸,并计算这两个对象之间的框架中心点

extension NSWindow {
    
    /// Positions the `NSWindow` at the horizontal-vertical center of the `visibleFrame` (takes Status Bar and Dock sizes into account)
    public func positionCenter() {
        if let screenSize = screen?.visibleFrame.size {
            self.setFrameOrigin(NSPoint(x: (screenSize.width-frame.size.width)/2, y: (screenSize.height-frame.size.height)/2))
        }
    }
    /// Centers the window within the `visibleFrame`, and sizes it with the width-by-height dimensions provided.
    public func setCenterFrame(width: Int, height: Int) {
        if let screenSize = screen?.visibleFrame.size {
            let x = (screenSize.width-frame.size.width)/2
            let y = (screenSize.height-frame.size.height)/2
            self.setFrame(NSRect(x: x, y: y, width: CGFloat(width), height: CGFloat(height)), display: true)
        }
    }
    /// Returns the center x-point of the `screen.visibleFrame` (the frame between the Status Bar and Dock).
    /// Falls back on `screen.frame` when `.visibleFrame` is unavailable (includes Status Bar and Dock).
    public func xCenter() -> CGFloat {
        if let screenSize = screen?.visibleFrame.size { return (screenSize.width-frame.size.width)/2 }
        if let screenSize = screen?.frame.size { return (screenSize.width-frame.size.width)/2 }
        return CGFloat(0)
    }
    /// Returns the center y-point of the `screen.visibleFrame` (the frame between the Status Bar and Dock).
    /// Falls back on `screen.frame` when `.visibleFrame` is unavailable (includes Status Bar and Dock).
    public func yCenter() -> CGFloat {
        if let screenSize = screen?.visibleFrame.size { return (screenSize.height-frame.size.height)/2 }
        if let screenSize = screen?.frame.size { return (screenSize.height-frame.size.height)/2 }
        return CGFloat(0)
    }

}

用法 NSWindow 将现有窗口定位到visibleFrame的中心

window!.positionCenter()
在visibleFrame的中心设置新窗框,并带有尺寸标注

window!.setCenterFrame(width: 900, height: 600)
NSView 使用
xCenter()
yCenter()
获取
可视框架的中心x-y点

let x = self.view.window?.xCenter() ?? CGFloat(0)
let y = self.view.window?.yCenter() ?? CGFloat(0)
self.view.window?.setFrame(NSRect(x: x, y: y, width: CGFloat(900), height: CGFloat(600)), display: true)
功能示例

override func viewDidLoad() {
    super.viewDidLoad()
    initWindowSize(width: 900, height: 600)
}

func initWindowSize(width: Int, height: Int) {
    let x = self.view.window?.xCenter() ?? CGFloat(0)
    let y = self.view.window?.yCenter() ?? CGFloat(0)
    self.view.window?.setFrame(NSRect(x: x, y: y, width: CGFloat(width), height: CGFloat(height)), display: true)
}

从“在Mac OS X上绘制自定义窗口”链接中获取顶部代码,NSScreen应在何处以及如何使用?@devilhunter:see@Wekwa-
[window screen]
返回当前窗口所在的
NSScreen
。如果您想将窗口放置在特定屏幕上,屏幕将给出所有窗口的列表,主要窗口等。查看示例xcode项目,没有“窗口”定义。(窗口未声明)。即使我将“window”声明为通过编程创建的“RoundWindow”,标题栏也会再次显示,因为它现在是一个普通的窗口类。请记住,为了正确显示多个窗口,还需要执行
xPos+=[[window screen]frame]。origin.x;yPos+=[[窗口屏幕]帧].origin.y@Glyph您所说的要点是正确的,但数学是错误的。根据显示排列,您需要进行不同的计算。例如,如果第二个屏幕位于主屏幕的左侧,则必须-=XPO。我还在弄清楚如何正确地计算所有屏幕布局。@BenBaron在计算出数学后请添加一个链接:)@Glyph我们终于计算出来了。我们的应用程序是开源的,因此请在此处查看updateWindowFrame和UpdateWindowrigin方法:
override func viewDidLoad() {
    super.viewDidLoad()
    initWindowSize(width: 900, height: 600)
}

func initWindowSize(width: Int, height: Int) {
    let x = self.view.window?.xCenter() ?? CGFloat(0)
    let y = self.view.window?.yCenter() ?? CGFloat(0)
    self.view.window?.setFrame(NSRect(x: x, y: y, width: CGFloat(width), height: CGFloat(height)), display: true)
}