You need to enable JavaScript to run this app. Mac OS菜单栏图标右键点击触发弹出功能菜单的实现问题
优惠活动
大模型
产品
解决方案
定价
更多

Mac OS菜单栏图标右键点击触发弹出功能菜单的实现问题

解决方案

你现在的核心问题是NSStatusBarButton扩展内的右键事件无法直接访问AppDelegate中的弹窗实例,也没有对应的逻辑触发选项弹窗,按以下步骤修改即可:


核心修改点

  1. 给选项弹窗popOverOptions补充基础行为配置,保证和主弹窗行为一致
  2. 给AppDelegate新增右键点击的处理方法,专门触发选项弹窗
  3. 在右键事件回调中关联AppDelegate的右键处理方法
  4. 弹窗触发逻辑中增加互斥判断,保证同一时间只有一个弹窗打开

修改后完整代码

@main
struct MenuNoteApp: App {
    let persistenceController = PersistenceController.shared
    @Environment(\.scenePhase) var scenePhase
    @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate
    var body: some Scene {
        WindowGroup {
            ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
        }
        .onChange(of: scenePhase) { _ in
            persistenceController.save()
        }
    }
}

extension NSStatusBarButton {
    open override func rightMouseUp(with event: NSEvent) {
        super.rightMouseUp(with: event)
        // 关联AppDelegate的右键处理逻辑
        guard let delegate = NSApplication.shared.delegate as? AppDelegate else { return }
        delegate.rightMenuButtonToggle(sender: self)
    }
}

class AppDelegate: NSObject,NSApplicationDelegate{
    let persistenceController = PersistenceController.shared
    // Status Item
    var statusItem: NSStatusItem?
    // PopOver
    var popOver = NSPopover()
    var popOverOptions = NSPopover()
    
    func applicationDidFinishLaunching(  _ notification: Notification){
        // Menu View
        let menuView = MenuView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
        
        // 主弹窗配置
        popOver.behavior = .transient
        popOver.animates = true
        popOver.contentViewController = NSViewController()
        popOver.contentViewController?.view = NSHostingView(rootView: menuView)
        
        // 选项弹窗补充配置
        popOverOptions.behavior = .transient
        popOverOptions.animates = true
        popOverOptions.contentViewController = NSViewController()
        popOverOptions.contentViewController?.view = NSHostingView(rootView: OptionsView())
        
        // 创建状态栏按钮
        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        if let MenuButton = statusItem?.button {
            MenuButton.image = NSImage(systemSymbolName: "note", accessibilityDescription: nil)
            MenuButton.action = #selector(MenuButtonToggle)
        }
    }
    
    // 左键点击处理
    @objc func MenuButtonToggle(sender: AnyObject){
        // 先关闭已打开的选项弹窗
        if popOverOptions.isShown{
            popOverOptions.performClose(sender)
        }
        if popOver.isShown{
            popOver.performClose(sender)
        } else {
            if let menuButton = statusItem?.button{
                self.popOver.show(relativeTo: menuButton.bounds, of: menuButton, preferredEdge: NSRectEdge.minY)
            }
        }
    }
    
    // 右键点击处理
    @objc func rightMenuButtonToggle(sender: AnyObject){
        // 先关闭已打开的主弹窗
        if popOver.isShown{
            popOver.performClose(sender)
        }
        if popOverOptions.isShown{
            popOverOptions.performClose(sender)
        } else {
            if let menuButton = statusItem?.button{
                self.popOverOptions.show(relativeTo: menuButton.bounds, of: menuButton, preferredEdge: NSRectEdge.minY)
            }
        }
    }
}

退出功能补充

如果需要在OptionsView中加退出按钮,直接在视图内添加以下代码即可:

Button("退出应用") {
    NSApplication.shared.terminate(nil)
}

内容的提问来源于stack exchange,提问作者marcus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 20:21:01