gpt4 book ai didi

macos - 从 NSStatusItem 显示主窗口时出现问题

转载 作者:行者123 更新时间:2023-12-03 18:07:28 28 4
gpt4 key购买 nike

我有一个仅限 NSStatusItem 的小型应用程序,带有设置窗口。从 NSStatusItem 中的菜单中,我想重新激活主窗口。

应用程序保留一个NSWindow实例,该实例设置为关闭时不释放。关闭窗口后,我将应用程序的激活策略更改为 accessory,因此 Dock 图标对用户隐藏起来。

当用户重新打开窗口时,我将激活策略更改回常规并再次显示该窗口。

这是隔离问题的示例应用程序中我的应用程序委托(delegate)的全部内容:

import Cocoa
import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

var window: NSWindow!
var statusItem: NSStatusItem!

func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the window and set the content view.
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.center()
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: EmptyView())
window.makeKeyAndOrderFront(nil)
window.isReleasedWhenClosed = false
window.delegate = self

statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
statusItem.button?.title = "X"
statusItem.button?.target = self
statusItem.button?.action = #selector(toggleWindow(sender:))

NSApp.setActivationPolicy(.accessory)
}

func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}

@objc func toggleWindow(sender: AnyObject) {
if window.isVisible {
window.close()
} else {
window.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
NSApp.setActivationPolicy(.regular)
}
}
}

extension AppDelegate: NSWindowDelegate {

func windowWillClose(_ notification: Notification) {
NSApp.setActivationPolicy(.accessory)
}

}

该应用程序是 Xcode 11 中的默认模板,但我将主视图更改为 EmptyView(),因此不需要额外的类。

如果我使用信号量按钮关闭窗口,然后使用状态栏图标重新打开它,则效果很好。

但是,如果我通过 CMD-W 关闭它并重新打开它,我会恢复窗口,但菜单仍保持选中状态,就好像之前的关闭命令尚未完成一样。

Menu with Edit selected

由于菜单处于这种奇怪的状态,因此应用程序不会响应事件,直到菜单问题得到解决(例如,通过单击另一个菜单项)。

更新:

作为解决方法,我发现如果我在几毫秒后更改激活策略,菜单问题就可以解决:

    func windowWillClose(_ notification: Notification) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
NSApp.setActivationPolicy(.accessory)
}
}

但是,窗口出现后,它仍然无法正确处理事件(错过了第一次点击)。

最佳答案

以下内容在我的系统上运行正常,并且没有显示有问题的行为;也许我误解了这个问题。这是一个可以在 Xcode 中运行的编程演示;由于某种原因,当脱离命令行运行时,所有菜单都不起作用。

import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
var statusItem: NSStatusItem!

@objc func showMainWindow() {
window.makeKeyAndOrderFront(nil)
}

@objc func hideMainWindow() {
window.orderOut(nil)
}

@objc func myBtnAction(_ sender:AnyObject ) {
NSSound.beep()
}

@objc func myMenuAction(_ sender:AnyObject ) {
NSSound.beep()
}

func buildMenu() {
let mainMenu = NSMenu()
NSApp.mainMenu = mainMenu
// **** App menu **** //
let appMenuItem = NSMenuItem()
mainMenu.addItem(appMenuItem)
let appMenu = NSMenu()
appMenuItem.submenu = appMenu
appMenu.addItem(withTitle: "Quit", action:#selector(NSApplication.terminate), keyEquivalent: "q")
// **** File menu **** //
let fileMenuItem = NSMenuItem()
let fileMenu = NSMenu(title: "File")
fileMenu.addItem(withTitle: "Beep", action:#selector(self.myMenuAction), keyEquivalent: "b")
fileMenuItem.submenu = fileMenu
mainMenu.addItem(fileMenuItem)
}

func buildWnd() {

let _wndW : CGFloat = 400
let _wndH : CGFloat = 300

window = NSWindow(contentRect:NSMakeRect(0,0,_wndW,_wndH),styleMask:[.titled, .miniaturizable, .resizable], backing:.buffered, defer:false)
window.center()
window.title = "Swift Test Window"

// **** TextView **** //
let scrlView = NSScrollView (frame:NSMakeRect( 10, 60, _wndW - 20, _wndH - 70 ))
window.contentView!.addSubview (scrlView)
scrlView.hasVerticalScroller = true
scrlView.autoresizingMask = [.height, .width]
let txtView = NSTextView (frame:NSMakeRect( 0, 0, _wndW - 20, _wndH - 70 ))
txtView.font = NSFont(name:"Menlo Bold", size: 13.0)
scrlView.documentView = txtView

// **** Button **** //
let myBtn = NSButton (frame:NSMakeRect( 150, 15, 95, 30 ))
myBtn.bezelStyle = .rounded
myBtn.autoresizingMask = [.minXMargin,.maxYMargin]
myBtn.title = "Beep"
myBtn.action = #selector(self.myBtnAction(_:))
window.contentView!.addSubview (myBtn)

// **** Quit btn **** //
let quitBtn = NSButton (frame:NSMakeRect( _wndW - 50, 10, 40, 40 ))
quitBtn.bezelStyle = .circular
quitBtn.autoresizingMask = [.minXMargin,.maxYMargin]
quitBtn.title = "Q"
quitBtn.action = #selector(NSApplication.terminate)
window.contentView!.addSubview(quitBtn)
}

func applicationDidFinishLaunching(_ aNotification: Notification) {
buildMenu()
buildWnd()
statusItem = NSStatusBar.system.statusItem(withLength: 100)
statusItem.button!.title = "foobar"
let menu = NSMenu()
let showMenuItem = NSMenuItem(title: "Show Window", action:#selector(self.showMainWindow), keyEquivalent: "")
menu.addItem(showMenuItem)
let hideMenuItem = NSMenuItem(title: "Hide Window", action:#selector(self.hideMainWindow), keyEquivalent: "")
menu.addItem(hideMenuItem)
menu.addItem(.separator())
menu.addItem(withTitle: "Quit", action:#selector(NSApplication.terminate), keyEquivalent: "q")
statusItem.menu = menu

}
}
let appDelegate = AppDelegate()

// **** main.swift **** //
let app = NSApplication.shared
app.setActivationPolicy(.regular)
app.delegate = appDelegate
app.activate(ignoringOtherApps:true)
app.run()

要在 Xcode 中运行,请创建一个 Swift 应用程序并添加一个 main.swift 文件(文件/新建/文件)。将导入 Foundation 更改为导入 Cocoa。从演示中复制/粘贴 main.swift 代码。完全删除旧的 AppDelegate 并复制/粘贴演示的 AppDelegate。点击运行。应该能够从状态栏中显示/隐藏主窗口。 TextView 始终将焦点保持在我的系统上。没有尝试过使用 xib。

关于macos - 从 NSStatusItem 显示主窗口时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61721352/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com