【问题标题】:macOS menubar application: main menu not being displayedmacOS 菜单栏应用程序:未显示主菜单
【发布时间】:2016-12-27 06:24:48
【问题描述】:

我有一个状态栏应用程序,它在菜单栏中运行。因此我在info.plst 中将Application is agent (UIElement) 设置为true。这导致我的应用程序没有停靠图标和菜单栏。

但是,我还有一个用户可以从状态栏菜单打开的首选项窗口。这是我打开它的方式:

if (!NSApp.setActivationPolicy(.regular)) {
    print("unable to set regular activation policy")
}
NSApp.activate(ignoringOtherApps: true)
if let window = preferencesWindowController.window {
    window.makeKeyAndOrderFront(nil)
}

窗口按预期显示,但应用程序的主菜单栏与 FileEdit 等没有显示。只有当我点击另一个应用程序并返回我的应用程序时,才会显示菜单栏。

我注意到,如果我将info.plst 中的值更改为false 并在applicationDidFinishLaunching() 中使用NSApp.setActivationPolicy(.accessory),则结果相同。但是,如果我在调用applicationDidFinishLaunching() 几毫秒后使用计时器调用NSApp.setActivationPolicy(.accessory),它会正常工作并且主菜单会按预期显示。但是,这会产生副作用,即应用程序图标会在 Dock 中弹出几秒钟(直到计时器被触发),这不是一个好的用户体验。

有人知道我还能尝试什么吗?当我切换活动的应用程序时发生了什么,我没有在代码中执行?

我在 macOS 10.12.2 (16C67) 上使用版本 8.2.1 (8C1002)

谢谢!

【问题讨论】:

  • “窗口按预期显示”我假设窗口也成为第一响应者,并且看起来不像在背景中或其他东西。对吗?
  • 我的应用程序也遇到了这个问题。你并不孤单:)

标签: swift macos cocoa background-process menubar


【解决方案1】:

这是我目前的解决方法解决方案:

正如我在问题中所写,如果我单击另一个应用程序并返回到我的应用程序,则会显示菜单栏。当我尝试显示首选项窗口时,我正在模拟这个:

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

这不是一个完美的解决方案。如果我没有找到更好的解决方案,我会提交一个错误。

【讨论】:

  • 我遇到了同样的问题,但我还没有找到可行的解决方案。你在哪里运行上面的代码?在 AppDelegate 的 applicationDidFinishLaunching 函数中?
  • 嗨!你有没有找到更好的解决方案?
  • 不,我没有。对不起。
【解决方案2】:

基于 OP 的修复(或解决方法)。真正的关键是切换并返回焦点(感谢@Daniel!)。

一些小的改进:

无需强制解包,无需设置ActivationPolicy和调用两次activate。

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

【讨论】:

  • 我用它来解决锁定与菜单栏交互的问题,当我使用应用程序的图标(保留在停靠栏中)重新打开以前的应用程序窗口时会发生这种情况隐藏进入状态栏应用状态
【解决方案3】:

我尝试使用苹果脚本,似乎按预期工作。

除非在按键关闭后重新打开一个新窗口(短时间间隔),菜单将保持选中状态。

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 演示:

Video link

【讨论】:

  • 感谢您的回答。注意:Apple Script 无法在 Mac App Store 上运行。如果你的应用是沙盒的,我认为它甚至根本不起作用。
  • 注意到 ?@Daniel
【解决方案4】:

我可能会为此找到另一个解决方案(这在 macOS 10.15 上仍然是一个问题)。我发现了一个类似的问题+解决方案here。这个想法即将显示和隐藏当前应用程序的 menuBar。我需要运行它 2 个不同的运行循环,但它有效。这是解决方案:

OperationQueue.main.addOperation {
    NSMenu.setMenuBarVisible(false)
    OperationQueue.main.addOperation {
        NSMenu.setMenuBarVisible(true)
    }
}

【讨论】:

  • 感谢您的建议。不幸的是菜单栏出现了,但是点击菜单栏项目不起作用。
【解决方案5】:

我找到了另一种解决方案,它不涉及聚焦停靠栏和后退,这会导致应用退出/进入焦点时闪烁。 这会将激活策略设置为禁止,然后在下一个滴答中定期:

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

【讨论】:

    猜你喜欢
    • 2017-05-15
    • 2020-05-05
    • 1970-01-01
    • 2015-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    相关资源
    最近更新 更多