是否仅在NSStatusBarButton上显示NSMenu右击?

人气:787 发布:2022-10-16 标签: cocoa swiftui swift macos appkit

问题描述

我有以下代码:(可以复制粘贴到新的MacOS项目)

import Cocoa
import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    var statusBarItem: NSStatusItem!

    func applicationDidFinishLaunching(_ aNotification: Notification) {

        let statusBar = NSStatusBar.system
        statusBarItem = statusBar.statusItem(
            withLength: NSStatusItem.squareLength)
        statusBarItem.button?.title = ""

        // Setting action
        statusBarItem.button?.action = #selector(self.statusBarButtonClicked(sender:))
        statusBarItem.button?.sendAction(on: [.leftMouseUp])

        let statusBarMenu = NSMenu(title: "Status Bar Menu")
        statusBarMenu.addItem(
            withTitle: "Order an apple",
            action: #selector(AppDelegate.orderAnApple),
            keyEquivalent: "")

        statusBarMenu.addItem(
            withTitle: "Cancel apple order",
            action: #selector(AppDelegate.cancelAppleOrder),
            keyEquivalent: "")

        // Setting menu
        statusBarItem.menu = statusBarMenu
    }

    @objc func statusBarButtonClicked(sender: NSStatusBarButton) {
        let event = NSApp.currentEvent!

        if event.type ==  NSEvent.EventType.rightMouseUp {
            print("Right click!")
        } else {
            print("Left click!")
        }
    }

    @objc func orderAnApple() {
        print("Ordering a apple!")
    }


    @objc func cancelAppleOrder() {
        print("Canceling your order :(")
    }

}

删除此行后:

statusBarItem.menu = statusBarMenu
所需行为:右击菜单打开,左击菜单未打开,操作被触发。如何实现?

编辑

我在@red_menace评论的帮助下成功实现了预期的行为:

import Cocoa
import SwiftUI

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    var statusBarItem: NSStatusItem!
    var menu: NSMenu!

    func applicationDidFinishLaunching(_ aNotification: Notification) {

        let statusBar = NSStatusBar.system
        statusBarItem = statusBar.statusItem(
            withLength: NSStatusItem.squareLength)
        statusBarItem.button?.title = ""

        // Setting action
        statusBarItem.button?.action = #selector(self.statusBarButtonClicked(sender:))
        statusBarItem.button?.sendAction(on: [.leftMouseUp, .rightMouseUp])

        let statusBarMenu = NSMenu(title: "Status Bar Menu")
        statusBarMenu.addItem(
            withTitle: "Order an apple",
            action: #selector(AppDelegate.orderAnApple),
            keyEquivalent: "")

        statusBarMenu.addItem(
            withTitle: "Cancel apple order",
            action: #selector(AppDelegate.cancelAppleOrder),
            keyEquivalent: "")

        // Setting menu
        menu = statusBarMenu
    }

    @objc func statusBarButtonClicked(sender: NSStatusBarButton) {
        let event = NSApp.currentEvent!

        if event.type ==  NSEvent.EventType.rightMouseUp {
            statusBarItem.popUpMenu(menu)
        } else {
            print("Left click!")
        }
    }

    @objc func orderAnApple() {
        print("Ordering a apple!")
    }


    @objc func cancelAppleOrder() {
        print("Canceling your order :(")
    }

}
有没有办法通过新的API实现所需的行为?

推荐答案

显示菜单的通常方式是将菜单分配给状态项,在单击状态项按钮时将在其中显示该菜单。由于popUpMenu已弃用,因此需要另一种方式来显示不同条件下的菜单。如果希望右击使用实际的状态项菜单,而不是仅在状态项位置显示上下文菜单,则状态项菜单属性可以保持为空,直到您想要显示它。

我对您的代码进行了修改,使statusBarItemstatusBarMenu引用保持分离,仅将菜单添加到单击的操作方法中的状态项。在操作方法中,一旦添加了菜单,就会在状态按钮上执行正常的单击以删除菜单。由于在单击按钮时状态项将始终显示其菜单,因此添加了NSMenuDelegate方法,以便在菜单关闭时将Menu属性设置为nil,从而恢复原始操作:

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
    // keep status item and menu separate
    var statusBarItem: NSStatusItem!
    var statusBarMenu: NSMenu!

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        let statusBar = NSStatusBar.system
        statusBarItem = statusBar.statusItem(withLength: NSStatusItem.squareLength)
        statusBarItem.button?.title = ""

        statusBarItem.button?.action = #selector(self.statusBarButtonClicked(sender:))
        statusBarItem.button?.sendAction(on: [.leftMouseUp, .rightMouseUp])

        statusBarMenu = NSMenu(title: "Status Bar Menu")
        statusBarMenu.delegate = self
        statusBarMenu.addItem(
            withTitle: "Order an apple",
            action: #selector(AppDelegate.orderAnApple),
            keyEquivalent: "")
        statusBarMenu.addItem(
            withTitle: "Cancel apple order",
            action: #selector(AppDelegate.cancelAppleOrder),
            keyEquivalent: "")
    }

    @objc func statusBarButtonClicked(sender: NSStatusBarButton) {
        let event = NSApp.currentEvent!
        if event.type ==  NSEvent.EventType.rightMouseUp {
            print("Right click!")
            statusBarItem.menu = statusBarMenu // add menu to button...
            statusBarItem.button?.performClick(nil) // ...and click
        } else {
            print("Left click!")
        }
    }

    @objc func menuDidClose(_ menu: NSMenu) {
        statusBarItem.menu = nil // remove menu so button works as before
    }

    @objc func orderAnApple() {
        print("Ordering a apple!")
    }

    @objc func cancelAppleOrder() {
        print("Canceling your order :(")
    }

}

962