macOS 菜单栏应用程序:未显示主菜单
macOS menubar application: main menu not being displayed
我有一个状态栏应用程序,它在菜单栏中运行。因此我在info.plst
中将Application is agent (UIElement)
设置为true
。这导致我的应用程序没有停靠栏图标和菜单栏。
不过,我还有一个偏好 window,用户可以从状态栏菜单中打开。这是我打开它的方式:
if (!NSApp.setActivationPolicy(.regular)) {
print("unable to set regular activation policy")
}
NSApp.activate(ignoringOtherApps: true)
if let window = preferencesWindowController.window {
window.makeKeyAndOrderFront(nil)
}
window 按预期显示,但应用程序的主菜单栏带有 File、Edit 等,没有出现。只有当我点击另一个应用程序并返回到我的应用程序时,才会显示菜单栏。
我注意到,如果我将 info.plst
中的值更改为 false
并在 applicationDidFinishLaunching()
中使用 NSApp.setActivationPolicy(.accessory)
,结果相同。但是,如果我在 applicationDidFinishLaunching()
被调用几毫秒后用计时器调用 NSApp.setActivationPolicy(.accessory)
,它会工作并且主菜单会按预期显示。然而,这有一个副作用,即应用程序图标会在 Dock 中弹出几秒钟(直到计时器被触发),这不是一个很好的用户体验。
有人知道我还能尝试什么吗?当我切换活动应用程序时发生了什么,我没有在代码中做?
我在 macOS 10.12.2 (16C67) 上使用版本 8.2.1 (8C1002)
谢谢!
这是我目前的解决方法解决方案:
正如我在问题中所写,如果我点击另一个应用程序并返回到我的应用程序,则会显示菜单栏。当我尝试显示偏好 window:
时,我正在模拟这个
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
window.makeKeyAndOrderFront(nil)
if (NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.dock").first?.activate(options: []))! {
let deadlineTime = DispatchTime.now() + .milliseconds(200)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
}
}
这不是一个完美的解决方案。如果找不到更好的解决方案,我会提交错误。
我尝试使用苹果脚本,显示按预期工作。
Except, after closing by key strokes and then reopening a new window (short time interval), menu will stay selected.
if NSApp.activationPolicy() == .accessory {
NSApp.setActivationPolicy(.regular)
} else {
var errorDict: NSDictionary?
NSAppleScript(source: """
tell application "Dock" to activate current application
""")?.executeAndReturnError(&errorDict)
if errorDict != nil{
print(errorDict!)
// error executing apple script
NSApp.activate(ignoringOtherApps: true)
}
}
window?.makeKeyAndOrderFront(self)
GIF 演示:
基于 OP 的修复(或解决方法)。关键真的是切换和返回焦点(感谢@Daniel!)。
一些小改进:
无需强制展开,无需设置ActivationPolicy和调用两次激活
NSApp.setActivationPolicy(.regular)
window.makeKeyAndOrderFront(nil)
NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.dock").first?.activate(options: [])
OperationQueue.current?.underlyingQueue?.asyncAfter(deadline: .now() + .milliseconds(200), execute: {
NSApp.activate(ignoringOtherApps: true)
})
我可能会为此找到另一个解决方案(这在 macOS 10.15 上仍然是一个问题)。我发现了一个类似的问题+解决方案here。这个想法是关于显示和隐藏当前应用程序的 menuBar。我需要 运行 它有 2 个不同的 运行 循环,但它起作用了。这是解决方案:
OperationQueue.main.addOperation {
NSMenu.setMenuBarVisible(false)
OperationQueue.main.addOperation {
NSMenu.setMenuBarVisible(true)
}
}
我找到了另一种解决方案,它不涉及对扩展坞和背面进行对焦,这会导致应用 exited/entered 对焦时出现闪烁。
这将激活策略设置为禁止,然后在下一个滴答中正常:
if NSApp.activationPolicy() != .regular {
NSApp.setActivationPolicy(.prohibited)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .milliseconds(200)) {
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
window.makeKeyAndOrderFront(nil)
}
} else {
// activation policy was already regular, just do normal window opening
NSApp.activate(ignoringOtherApps: true)
window.makeKeyAndOrderFront(nil)
}
我有一个状态栏应用程序,它在菜单栏中运行。因此我在info.plst
中将Application is agent (UIElement)
设置为true
。这导致我的应用程序没有停靠栏图标和菜单栏。
不过,我还有一个偏好 window,用户可以从状态栏菜单中打开。这是我打开它的方式:
if (!NSApp.setActivationPolicy(.regular)) {
print("unable to set regular activation policy")
}
NSApp.activate(ignoringOtherApps: true)
if let window = preferencesWindowController.window {
window.makeKeyAndOrderFront(nil)
}
window 按预期显示,但应用程序的主菜单栏带有 File、Edit 等,没有出现。只有当我点击另一个应用程序并返回到我的应用程序时,才会显示菜单栏。
我注意到,如果我将 info.plst
中的值更改为 false
并在 applicationDidFinishLaunching()
中使用 NSApp.setActivationPolicy(.accessory)
,结果相同。但是,如果我在 applicationDidFinishLaunching()
被调用几毫秒后用计时器调用 NSApp.setActivationPolicy(.accessory)
,它会工作并且主菜单会按预期显示。然而,这有一个副作用,即应用程序图标会在 Dock 中弹出几秒钟(直到计时器被触发),这不是一个很好的用户体验。
有人知道我还能尝试什么吗?当我切换活动应用程序时发生了什么,我没有在代码中做?
我在 macOS 10.12.2 (16C67) 上使用版本 8.2.1 (8C1002)
谢谢!
这是我目前的解决方法解决方案:
正如我在问题中所写,如果我点击另一个应用程序并返回到我的应用程序,则会显示菜单栏。当我尝试显示偏好 window:
时,我正在模拟这个 NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
window.makeKeyAndOrderFront(nil)
if (NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.dock").first?.activate(options: []))! {
let deadlineTime = DispatchTime.now() + .milliseconds(200)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
}
}
这不是一个完美的解决方案。如果找不到更好的解决方案,我会提交错误。
我尝试使用苹果脚本,显示按预期工作。
Except, after closing by key strokes and then reopening a new window (short time interval), menu will stay selected.
if NSApp.activationPolicy() == .accessory {
NSApp.setActivationPolicy(.regular)
} else {
var errorDict: NSDictionary?
NSAppleScript(source: """
tell application "Dock" to activate current application
""")?.executeAndReturnError(&errorDict)
if errorDict != nil{
print(errorDict!)
// error executing apple script
NSApp.activate(ignoringOtherApps: true)
}
}
window?.makeKeyAndOrderFront(self)
GIF 演示:
基于 OP 的修复(或解决方法)。关键真的是切换和返回焦点(感谢@Daniel!)。
一些小改进:
无需强制展开,无需设置ActivationPolicy和调用两次激活
NSApp.setActivationPolicy(.regular)
window.makeKeyAndOrderFront(nil)
NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.dock").first?.activate(options: [])
OperationQueue.current?.underlyingQueue?.asyncAfter(deadline: .now() + .milliseconds(200), execute: {
NSApp.activate(ignoringOtherApps: true)
})
我可能会为此找到另一个解决方案(这在 macOS 10.15 上仍然是一个问题)。我发现了一个类似的问题+解决方案here。这个想法是关于显示和隐藏当前应用程序的 menuBar。我需要 运行 它有 2 个不同的 运行 循环,但它起作用了。这是解决方案:
OperationQueue.main.addOperation {
NSMenu.setMenuBarVisible(false)
OperationQueue.main.addOperation {
NSMenu.setMenuBarVisible(true)
}
}
我找到了另一种解决方案,它不涉及对扩展坞和背面进行对焦,这会导致应用 exited/entered 对焦时出现闪烁。 这将激活策略设置为禁止,然后在下一个滴答中正常:
if NSApp.activationPolicy() != .regular {
NSApp.setActivationPolicy(.prohibited)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .milliseconds(200)) {
NSApp.setActivationPolicy(.regular)
NSApp.activate(ignoringOtherApps: true)
window.makeKeyAndOrderFront(nil)
}
} else {
// activation policy was already regular, just do normal window opening
NSApp.activate(ignoringOtherApps: true)
window.makeKeyAndOrderFront(nil)
}