center programmatically created window

廉价感情. 提交于 2021-02-18 05:32:29

问题


I've been using the example from here to create a custom titlebar-less window:

Drawing a custom window on Mac OS X

I've found this is the only way i can create a titlebar-less window in Leopard, Snow Leopard and Lion, other methods don't work right either on Leopard or Lion. (If i try to invoke a titlebar-less window via normal NSWindow and IB, it won't start up in Leopard anymore)

So far this custom titlebar-less window works great everywhere, but i can't center it, only a hard fixed position in Interface Builder.

It's fairly easy to center a normal NSWindow *window implementation with [window center], but i've found nothing that works on this custom window subclass, a window that isn't created from nib via Interface Builder.

I've tried a few things from NSWindow, but nothing seems to work.

Any Ideas?


回答1:


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];

This puts it at the literal center of the screen, not taking into account the space occupied by the dock and menu bar. If you want to do that, change [[window screen] frame] to [[window screen] visibleFrame].




回答2:


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



回答3:


The question should probably be why [window center] does not work; but assuming that is the case use NSScreen to get the screen coordinates, do the math, and center the window directly.




回答4:


I stumbled on the same issue. What worked for me is to set isRestorable to false on the NSWindow object before calling center().




回答5:


Objective - C in macOS Catalina , Version 10.15.3

more readable @Wekwa's answer

- (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];
}



回答6:


Swift version: One can write a simple static utility function for the same

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



回答7:


Updated for Swift 5

I always found that centering the window with screen.frame resulted in a window that feels as if it were too close to the bottom of the screen. This is due to the Dock size being nearly 3x as large as the Status/Menu Bar (roughly 70-80px vs. 25px, respectively).

This causes the window to appear as if it were positioned lower to the bottom of the screen, as our eyes do not automatically adjust the insets of the Status Bar (1x size) and the Dock (~3x size).

For this reason, I always choose to go to with screen.visibleFrame, as it definitely feels more centered. visibleFrame takes both the Status Bar and Dock sizes into consideration, and calculates the central points for the frame between those two objects.

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

}

Usage

NSWindow

Positions the existing window to the center of visibleFrame.

window!.positionCenter()

Sets a new window frame, at the center of visibleFrame, with dimensions

window!.setCenterFrame(width: 900, height: 600)

NSView

Using xCenter() and yCenter() to get the central x-y points of the visibleFrame.

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)

Function Example

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


来源:https://stackoverflow.com/questions/5682712/center-programmatically-created-window

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!