从菜单栏打开窗口(SwiftUI、MacOS)

ivk*_*mer 5 macos appdelegate swiftui

我开始开发一款适用于 MacOS 的应用程序,但遇到了几个问题。其中之一如下。

\n

我有一个 UIElement 应用程序。

\n

它通过以下方式初始化:

\n
@main\nstruct MyApp: App {\n    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate\n\n    var body: some Scene {\n        Settings {\n            EmptyView()\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在我的 AppDelegate.swift 中我有:

\n
import SwiftUI\n\nclass AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {\n    static private(set) var instance: AppDelegate!\n    var settingsWindow: NSWindow!\n    lazy var statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)\n    let menu = AppMenu()\n    \n    func applicationDidFinishLaunching(_ notification: Notification) {\n        statusBarItem.button?.image = NSImage(\n            systemSymbolName: "circle",\n            accessibilityDescription: "My App"\n        )\n        statusBarItem.menu = menu.createMenu()\n    }\n\n    @objc func openSettingsWindow() {\n        if settingsWindow == nil {\n            let settingsView = SettingsView()\n            settingsWindow = NSWindow(\n                contentRect: NSRect(x: 20, y: 20, width: 480, height: 300),\n                styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],\n                backing: .buffered,\n                defer: false\n            )\n            settingsWindow.center()\n            settingsWindow.title = "Settings"\n            settingsWindow.isReleasedWhenClosed = false\n            settingsWindow.contentView = NSHostingView(rootView: settingsView)\n        }\n        settingsWindow.makeKeyAndOrderFront(nil)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

最后,菜单是这样构建的:

\n
import SwiftUI\n\nclass AppMenu: NSObject {\n    let menu = NSMenu()\n\n    func createMenu() -> NSMenu {\n        // ...\n        let settingsMenuItem = NSMenuItem(title: "Settings", action: #selector(settings), keyEquivalent: ",")\n        settingsMenuItem.target = self\n        menu.addItem(settingsMenuItem)\n        // ...\n        return menu\n    }\n\n    @objc func settings(sender: NSMenuItem) {\n        NSApp.sendAction(#selector(AppDelegate.openSettingsWindow), to: nil, from: nil)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但是,当我在菜单栏中打开应用程序并点击“设置”时,窗口SettingsView会随机显示(我不确定它被打开和不打开的确切原因是什么)。

\n

在 Xcode 的日志部分我看到警告:

\n
2023-05-29 21:39:57.172266+0200 My App[2211:1474025] [Window] Warning: Window NSMenuWindowManagerWindow 0x7fb8d4e21640 ordered front from a non-active application and may order beneath the active application's windows.\n2023-05-29 21:40:02.197549+0200 My App[2211:1474025] [Window] Warning: Window NSWindow 0x7fb8d3717790 ordered front from a non-active application and may order beneath the active application's windows.\n
Run Code Online (Sandbox Code Playgroud)\n

当我点击菜单栏中的应用程序图标(每次)时,会触发第一个警告;当单击“设置”时,会触发第二个 \xe2\x80\x93 。

\n

我的目标是拥有一个在 docker 中没有窗口的应用程序,但有机会通过其菜单栏项目打开不同的窗口。

\n

sou*_*lix 5

我认为您的设置窗口每次都会打开,但从状态栏菜单调用不会激活您的应用程序。因此,它隐藏在其他窗口下。

选项 1:激活您的应用程序

settingsWindow.makeKeyAndOrderFront(nil)

NSApp.activate(ignoringOtherApps: true) // add this
Run Code Online (Sandbox Code Playgroud)

选项 2:升高车窗高度

settingsWindow.level = NSWindow.Level.init(rawValue: 1)  // add this

settingsWindow.makeKeyAndOrderFront(nil)
Run Code Online (Sandbox Code Playgroud)

如果您想要一个没有 Dock 图标的应用程序,请将其添加到您的 Info.plist 中:

LSUIElement = TRUE
Run Code Online (Sandbox Code Playgroud)