英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论