如何以编程方式添加 NSMenu?

Posted

技术标签:

【中文标题】如何以编程方式添加 NSMenu?【英文标题】:How to add NSMenu Programmatically? 【发布时间】:2015-05-01 03:54:35 【问题描述】:

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

1)如何显示“编辑”菜单/评论问题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
    

【问题讨论】:

如果您确实需要,请您说明为什么要制作一个没有主菜单的应用程序? 我使用自定义代码的原因是1)我想做的类似于github.com/devxoul/allkdic(自定义代码)2)如果您知道如何编写用户界面,那么您就会知道会发生什么在引擎盖下,而对于 NIB 和 Storyboard 则不一定如此。 老实说,这根本没有任何意义。如果你需要一个菜单​​(并且你声明你确实需要它),那么使用 MainMenu 作为放置在 Info.plist 中。 我不太了解所有的负面因素。这是一个完全合理的问题,我也想知道答案。我想插入和附加项目。即不是静态的而是动态的。这适用于从动态菜单下载和启动应用程序的启动器应用程序。 【参考方案1】:

你没有显示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:"

【讨论】:

感谢您的回答。我没有足够的声望。我会尝试这样做并再次发表评论。谢谢你,肯。 我确实喜欢这个,gist.github.com/AstinCHOI/9791f4b0ab941a2be6da。但它没有用。感谢您的帮助。 您遗漏了mainMenu?.addItem(editMenuItem) 声明。 当前的要点已将其注释掉。另外,检查mainMenu 不是nil 如你所料,mainMenu 为 nil T.T【参考方案2】:

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

自动菜单启用

如果菜单项的目标未设置(也就是说,如果它为 nil,通常如果菜单项连接到 First Responder)并且 NSMenu 对象不是上下文菜单,然后 NSMenu 使用响应者链(在响应者链中描述)来确定目标。如果在响应者链中没有没有对象来实现该项目的操作,则该项目被禁用。 如果在响应者链中有一个对象实现了项目的动作,NSMenu 然后检查该对象是否实现了validateMenuItem:validateUserInterfaceItem: 方法。如果它没有,则菜单项启用。如果是,则菜单项的启用状态由方法的返回值确定。

因此,为了实现标准系统菜单项的自动菜单启用,我们必须指定正确的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")

【讨论】:

【参考方案3】:

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

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

我的环境是:Xcode 12.3、macOS 10.15.7、Swift 5.3.2

【讨论】:

以上是关于如何以编程方式添加 NSMenu?的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式创建带有 NSMenuItems 的 NSMenu?

我可以以编程方式打开 NSMenu 吗?

以编程方式更改核心数据文件中的数据

使用动作选择器预设将项目添加到 NSMenu

如何以编程方式使用自动布局以编程方式添加 UIview?

如何以编程方式添加标签并以编程方式使用自动布局定位它