如何以编程方式添加 NSMenu?

How to add NSMenu Programmatically?

我没有用storyboard和xib,只用了代码。 我想以编程方式添加 "Edit" 菜单。我的问题是

1) 如何显示"Edit" 菜单/评论问题1) 需要输入什么代码?

2) swift 提供了任何操作,例如复制和粘贴?

class TestManager: NSObject {

// ....
    override init() {
        let editMenuItems = [
            NSMenuItem(title: "Cut", action: nil(/* Question 2) */), keyEquivalent: ""),
            NSMenuItem(title: "Copy", action: nil, keyEquivalent: ""),
            NSMenuItem(title: "Paste", action: nil, keyEquivalent: ""),
        ]

        for editMenuItem in editMenuItems {
            self.editMenu.addItem(editMenuItem)
        }

        // Qustion 1) .. show "Edit" Menu
    }
}

你没有显示 self.editMenu 的来源。

在任何情况下,您都需要从 NSApplication 实例中获取 mainMenu 并将菜单项添加到以您的菜单作为其子菜单的菜单项。所以,像这样:

var editMenuItem = NSMenuItem()
editMenuItem.title = "Edit"
var mainMenu = NSMenu()
mainMenu.addItem(editMenuItem)
mainMenu.setSubmenu(self.editMenu, forItem:editMenuItem)
NSApplication.sharedApplication().mainMenu = mainMenu

我不在Swift工作,所以里面可能有一些错误。

至于编辑菜单项使用什么操作选择器,最简单的方法是创建一个主菜单 NIB 来检查它。查看用于现成编辑菜单的菜单项的操作选择器。例如,您会发现 Copy 项使用 copy: 选择器。这可以在 Swift 中表示为一个字符串,"copy:".

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/MenuList/Articles/EnablingMenuItems.html

Automatic Menu Enabling

  • If the menu item’s target is not set (that is, if it is nil—typically if the menu item is connected to First Responder) and the NSMenu object is not a contextual menu, then NSMenu uses the responder chain (described in The Responder Chain) to determine the target. If there is no object in the responder chain that implements the item’s action, the item is disabled. If there is an object in the responder chain that implements the item’s action, NSMenu then checks to see if that object implements the validateMenuItem: or validateUserInterfaceItem: method. If it does not, then the menu item is enabled. If it does, then the enabled status of the menu item is determined by the return value of the method.

因此,为了实现 自动菜单启用 标准系统 菜单项,我们必须指定正确的 action设置 target.

let menu = NSMenu(...)
menu.addItem(withTitle: "Quit \(applicationName)",
             action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")
menu.addItem(withTitle: "Select All",
             action: #selector(NSText.selectAll(_:)), keyEquivalent: "a")
menu.addItem(withTitle: "Copy",
             action: #selector(NSText.copy(_:)), keyEquivalent: "c")

我发现这里的答案大体上是正确的,但缺少一些东西,所以我将添加我的完整解决方案。就我而言,我只想为开发添加一个“调试”菜单。

func addDebugMenu() {
    let debugMenu = NSMenuItem(title: "Debug", action: nil, keyEquivalent: "")
    debugMenu.submenu = NSMenu(title: "Debug")
    debugMenu.submenu?.addItem(withTitle: "Load saved data", action: #selector(self.loadDataFromFile(_:)), keyEquivalent: "")
    NSApplication.shared.mainMenu?.addItem(debugMenu)
}

@objc func loadDataFromFile(_ sender: Any) {
    print("load it")
}

对于完整的解决方案,仅供开发人员这样称呼:

#if DEBUG
addDebugMenu()
#endif

我的环境是:Xcode12.3,macOS 10.15.7,Swift5.3.2