#cocoa #center #nswindow
#cocoa #центр #nswindow
Вопрос:
Я использовал приведенный здесь пример для создания пользовательского окна без заголовка:
Рисование пользовательского окна в Mac OS X
Я обнаружил, что это единственный способ создать окно без заголовка в Leopard, Snow Leopard и Lion, другие методы не работают должным образом ни в Leopard, ни в Lion. (Если я попытаюсь вызвать окно без заголовка через обычный NSWindow и IB, оно больше не запустится в Leopard)
Пока что это пользовательское окно без заголовка отлично работает везде, но я не могу его центрировать, только жестко зафиксированное положение в Interface Builder.
Довольно легко центрировать обычную реализацию окна NSWindow * с помощью [window center], но я не нашел ничего, что работало бы в этом пользовательском подклассе window, окне, которое не создается из nib через Interface Builder.
Я попробовал несколько вещей из 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];
Это помещает его буквально в центр экрана, не принимая во внимание пространство, занимаемое dock и строкой меню. Если вы хотите это сделать, измените [[window screen] frame]
на [[window screen] visibleFrame]
.
Комментарии:
1. Глядя на пример проекта xcode, нет определения «окна». (окно не объявлено). даже если я объявляю ‘window’ для программно созданного ‘RoundWindow’, строка заголовка отображается снова, потому что теперь это обычный класс window.
2. Имейте в виду, что для корректного отображения на нескольких дисплеях вам также необходимо выполнить
xPos = [[window screen] frame].origin.x; yPos = [[window screen] frame].origin.y;
3. @Glyph суть того, что вы говорите, верна, но математика неверна. В зависимости от настроек отображения вам нужно выполнить разные вычисления. Например, если второй экран находится слева от главного экрана, вы должны -= xPos. Я все еще выясняю, как правильно выполнить вычисления для всех экранных компоновок.
4. @BenBaron Пожалуйста, добавьте ссылку, когда разберетесь с этой математикой 🙂
5. @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
, чтобы получить координаты экрана, выполнить вычисления и напрямую отцентрировать окно.
Комментарии:
1. Берем верхний код из ссылки «Рисование пользовательского окна в Mac OS X», где и как следует использовать NSScreen там?
2. @devilhunter: смотрите @Wekwa —
[window screen]
возвращаетNSScreen
значение, в котором окно находится в данный момент. Если вы хотите разместить окно на определенном экранеNSScreen
, вам будет предоставлен список их всех, основного и т.д.
Ответ №4:
Objective — 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:
Обновлено для Swift 5
Я всегда обнаруживал, что центрирование окна с помощью screen.frame
приводит к тому, что окно кажется расположенным слишком близко к нижней части экрана. Это связано с тем, что размер док-станции почти в 3 раза больше, чем строка состояния / меню (примерно 70-80 пикселей против 25 пикселей соответственно).
Это приводит к тому, что окно появляется так, как если бы оно было расположено ниже нижней части экрана, поскольку наши глаза автоматически не настраивают вставки строки состояния (размер 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 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)
Пример функции
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)
}
Ответ №6:
Я наткнулся на ту же проблему. Что сработало для меня, так это установить isRestorable
значение false
для NSWindow
объекта перед вызовом center()
.
Ответ №7:
Версия 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)
}
}