【问题标题】:Center programmatically created window居中以编程方式创建的窗口
【发布时间】:2011-08-06 15:57:19
【问题描述】:

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

Drawing a custom window on 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


    【解决方案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];
    

    这将它放在屏幕的文字中心,而不考虑停靠栏和菜单栏占用的空间。如果您想这样做,请将[[window screen] frame] 更改为[[window screen] visibleFrame]

    【讨论】:

    • 查看示例 xcode 项目,没有“窗口”定义。 (窗口未声明)。即使我向以编程方式创建的“RoundWindow”声明“窗口”,标题栏也会再次显示,因为它现在是一个普通的窗口类。
    • 请记住,为了正确显示多个显示器,您还需要这样做xPos += [[window screen] frame].origin.x; yPos += [[window screen] frame].origin.y;
    • @Glyph 你所说的要点是正确的,但数学是错误的。根据显示安排,您需要进行不同的计算。例如,如果第二个屏幕位于主屏幕的左侧,则您必须 -= xPos。我仍在研究如何为所有屏幕安排正确计算。
    • @BenBaron 当你算出数学时请添加一个链接:)
    • @Glyph 我们终于弄明白了。我们的应用是开源的,因此请在此处查看 updateWindowFrame 和 updateWindowOrigin 方法:github.com/balancemymoney/balance-open/blob/master/Balance/…
    【解决方案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】:

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

      【讨论】:

      • 从“在 Mac OS X 上绘制自定义窗口”链接中获取顶部代码,NSScreen 应该在哪里以及如何使用?
      • @devilhunter:见@Wekwa - [window screen] 返回NSScreen,即窗口当前打开的那个。如果您想将窗口放置在特定屏幕上,NSScreen 将为您提供所有这些窗口的列表、主要窗口等。
      【解决方案4】:

      目标 - C 在 macOS Catalina 版本 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];
      }
      

      【讨论】:

        【解决方案5】:

        我偶然发现了同样的问题。对我有用的是在调用center() 之前将NSWindow 对象上的isRestorable 设置为false

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

            为 Swift 5 更新

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

            这会导致窗口出现就好像它位于屏幕底部的下方,因为我们的眼睛不会自动调整状态栏(1x 大小)和 Dock ( ~3x 大小)。

            出于这个原因,我总是选择使用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)
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-06-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-10-26
              • 1970-01-01
              • 2019-06-25
              • 1970-01-01
              相关资源
              最近更新 更多