打开菜单栏中的窗口(SwiftUI,MacOS)

huangapple go评论48阅读模式
英文:

Open a window from menu bar (SwiftUI, MacOS)

问题

以下是您提供的内容的中文翻译:

我开始为MacOS开发一个应用程序,但遇到了一些问题。其中之一是以下问题。

我有一个UI元素的应用程序。

它的初始化方式如下:

@main
struct MyApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        Settings {
            EmptyView()
        }
    }
}

在我的AppDelegate.swift中,我有:

import SwiftUI

class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
    static private(set) var instance: AppDelegate!
    var settingsWindow: NSWindow!
    lazy var statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
    let menu = AppMenu()
    
    func applicationDidFinishLaunching(_ notification: Notification) {
        statusBarItem.button?.image = NSImage(
            systemSymbolName: "circle",
            accessibilityDescription: "My App"
        )
        statusBarItem.menu = menu.createMenu()
    }

    @objc func openSettingsWindow() {
        if settingsWindow == nil {
            let settingsView = SettingsView()
            settingsWindow = NSWindow(
                contentRect: NSRect(x: 20, y: 20, width: 480, height: 300),
                styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
                backing: .buffered,
                defer: false
            )
            settingsWindow.center()
            settingsWindow.title = "Settings"
            settingsWindow.isReleasedWhenClosed = false
            settingsWindow.contentView = NSHostingView(rootView: settingsView)
        }
        settingsWindow.makeKeyAndOrderFront(nil)
    }
}

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

import SwiftUI

class AppMenu: NSObject {
    let menu = NSMenu()

    func createMenu() -> NSMenu {
        // ...
        let settingsMenuItem = NSMenuItem(title: "Settings", action: #selector(settings), keyEquivalent: ",")
        settingsMenuItem.target = self
        menu.addItem(settingsMenuItem)
        // ...
        return menu
    }

    @objc func settings(sender: NSMenuItem) {
        NSApp.sendAction(#selector(AppDelegate.openSettingsWindow), to: nil, from: nil)
    }
}

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

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

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.
2023-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.

第一个警告在我点击菜单栏中的应用程序图标时触发(每次都是如此),第二个警告在点击“设置”时触发。

我的目标是在docker中创建一个没有窗口但可以通过其菜单栏项打开不同窗口的应用程序。

英文:

I started working on an app for MacOS and got stuck on several issues. One of them is the following.

I have a UIElement app.

It's initialized in the following way:

@main
struct MyApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        Settings {
            EmptyView()
        }
    }
}

In my AppDelegate.swift I have:

import SwiftUI

class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
    static private(set) var instance: AppDelegate!
    var settingsWindow: NSWindow!
    lazy var statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
    let menu = AppMenu()
    
    func applicationDidFinishLaunching(_ notification: Notification) {
        statusBarItem.button?.image = NSImage(
            systemSymbolName: "circle",
            accessibilityDescription: "My App"
        )
        statusBarItem.menu = menu.createMenu()
    }

    @objc func openSettingsWindow() {
        if settingsWindow == nil {
            let settingsView = SettingsView()
            settingsWindow = NSWindow(
                contentRect: NSRect(x: 20, y: 20, width: 480, height: 300),
                styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
                backing: .buffered,
                defer: false
            )
            settingsWindow.center()
            settingsWindow.title = "Settings"
            settingsWindow.isReleasedWhenClosed = false
            settingsWindow.contentView = NSHostingView(rootView: settingsView)
        }
        settingsWindow.makeKeyAndOrderFront(nil)
    }
}

And the last, the menu is built like this:

import SwiftUI

class AppMenu: NSObject {
    let menu = NSMenu()

    func createMenu() -> NSMenu {
        // ...
        let settingsMenuItem = NSMenuItem(title: "Settings", action: #selector(settings), keyEquivalent: ",")
        settingsMenuItem.target = self
        menu.addItem(settingsMenuItem)
        // ...
        return menu
    }

    @objc func settings(sender: NSMenuItem) {
        NSApp.sendAction(#selector(AppDelegate.openSettingsWindow), to: nil, from: nil)
    }
}

But when I open the app in the menu bar and hit Settings the window with SettingsView is displayed randomly (I'm not sure what is exactly the reason for it being opened and not).

In the log section of Xcode I see warnings:

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.
2023-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.

The first warning is fired when I hit the app icon in the menu bar (every time) and the second – when Settings is clicked.

My goal is to have an app without a window in docker but with an opportunity to open different windows via its menu bar items.

答案1

得分: 3

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

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

settingsWindow.makeKeyAndOrderFront(nil)

NSApp.activate(ignoringOtherApps: true) // 添加这行

选项2: 提升窗口级别

settingsWindow.level = NSWindow.Level.init(rawValue: 1) // 添加这行

settingsWindow.makeKeyAndOrderFront(nil)

如果你希望应用程序没有 Dock 图标,请在 Info.plist 中添加以下内容:

LSUIElement = TRUE
英文:

I think your settings window is opening each time, but calling from your status bar menu does not activate your app. Thus, it's hidden under other windows.

Option 1: Activate your app

settingsWindow.makeKeyAndOrderFront(nil)

NSApp.activate(ignoringOtherApps: true) // add this

Option 2: Raise window level

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

settingsWindow.makeKeyAndOrderFront(nil)

If you want an app without Dock icon, add this in your Info.plist:

LSUIElement = TRUE

huangapple
  • 本文由 发表于 2023年5月30日 03:45:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76359975.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定