以编程方式创建的窗口居中

问题描述 投票:0回答:8

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

在 Mac OS X 上绘制自定义窗口

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

到目前为止,这个自定义的无标题栏窗口在任何地方都可以很好地工作,但我无法将其居中,只能在 Interface Builder 中进行硬固定位置。

使用 [window center] 将普通 NSWindow *window 实现居中是相当容易的,但我发现没有任何东西适用于此自定义窗口子类,该窗口不是通过 Interface Builder 从 nib 创建的。

我尝试了 NSWindow 中的一些方法,但似乎没有任何效果。

有什么想法吗?

cocoa center nswindow
8个回答
21
投票
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];

这会将其放置在屏幕的文字中心,而不考虑停靠栏和菜单栏占用的空间。如果您想这样做,请将

[[window screen] frame]
更改为
[[window screen] visibleFrame]


10
投票
extension NSWindow {
    public func setFrameOriginToPositionWindowInCenterOfScreen() {
        if let screenSize = screen?.frame.size {
            self.setFrameOrigin(NSPoint(x: (screenSize.width-frame.size.width)/2, y: (screenSize.height-frame.size.height)/2))
        }
    }
}

4
投票

问题可能应该是为什么

[window center]
不起作用;但假设是这种情况,请使用
NSScreen
获取屏幕坐标,进行数学计算,然后直接将窗口居中。


3
投票

目标 - macOS Catalina 中的 C,版本 10.15.3

更具可读性的@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];
}

2
投票

针对 Swift 5 进行了更新

我总是发现用

screen.frame
使窗口居中会导致窗口 感觉 好像离屏幕底部太近。这是因为 Dock 大小几乎是状态/菜单栏的 3 倍(分别约为 70-80 像素和 25 像素)。

这会导致窗口出现,就好像它位于屏幕底部较低的位置,因为我们的眼睛不会自动调整状态栏(1 倍大小)和 Dock(〜3 倍大小)的插入。

出于这个原因,我总是选择去

screen.visibleFrame
,因为它绝对感觉更集中。
visibleFrame
同时考虑状态栏和 Dock 大小,并计算这两个对象之间框架的中心点。

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()
获取
visibleFrame
的中心 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)
}

1
投票

我偶然发现了同样的问题。对我有用的是在调用

isRestorable
之前将
false
对象上的
NSWindow
设置为
center()


0
投票

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)
        }
}

0
投票

NSWindow 有一个属性 screen,其中有一个属性 visibleFrame。此属性的工作方式类似于 safeArea(不包括菜单栏和停靠栏的屏幕框架)。 NSWindow 扩展有 Swift 代码。

extension NSWindow {
    func centerOnScreen() {
        guard let screen else {
            return
        }
        
        let screenFrame = screen.visibleFrame
        let windowFrame = frame
        
        let xPosition = screenFrame.width / 2 - windowFrame.width / 2
        let yPosition = screenFrame.height / 2 - windowFrame.height / 2
        let origin = NSPoint(x: xPosition, y: yPosition)
        setFrameOrigin(origin)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.