繁体   English   中英

如何摆脱 MacOS 中自动添加的菜单项?

[英]How to get rid of automatically added menu items in MacOS?

在 MacOS 顶部菜单栏的Edit部分,它不断添加Start Dictation...Emoji & Symbols ,即使它不在Xcode 中 这是最后两个用红色圈出的不需要的项目的屏幕截图 我无法删除它们,因为它们不存在于 Xcode UI 构建器中,但它们会以某种方式自动添加。 我怎样才能摆脱它们?

我不允许在应用程序启动时以编程方式删除它们。 我首先需要阻止它们。

我试图用新创建的菜单替换当前的编辑菜单,删除旧菜单并转移项目,但没有成功。 我也尝试将它重命名为另一个名称,也没有占上风。

我的代码是 Swift,所以 ObjC 的答案对我没有帮助,最重要的是,我不允许在程序以编程方式启动后手动删除它们。

提前致谢!

我发布了一个答案,该答案使用 Swift 和选择器来解决 Willeke 链接到的问题。 我不会在这里重复该解决方案,但最后我提到了另一种方法,我将在这里详细介绍。

首先,我要说这个解决方案有点重量级,但它对于 Apple 未来可能选择添加的任何自动菜单也很强大。 它最适合以编程方式创建菜单。 可以将它与 Storyboards 一起使用,但这更麻烦。

这个想法是在不依赖未记录的UserDefaults设置的情况下首先防止添加不需要的菜单。

为此,您需要控制添加菜单项的过程。 这发生在NSMenu ,因此计划是对其进行子类化,覆盖各种addItem / insertItem方法以检查tag的任何NSMenuItemtag属性。 如果标签与您为应用定义的某个值不匹配,只需拒绝添加该项目。

不幸的是NSMenu不不调用addItem(_:)当你调用addItem(withTitle:action:keyEquivalent)也为insertItem方法,所以你必须覆盖所有的人而不是两个。

进行一些调试打印也很有帮助,尤其是在使用 Storyboard 时,因为很容易错过标记菜单项。

class TaggedItemMenu: NSMenu
{
    static let wantedTag = 42 // or whatever value
    
    // Helper for creating properly tagged menu items
    private func makeTaggedItem(
        withTitle string: String,
        action selector: Selector?,
        keyEquivalent charCode: String) -> NSMenuItem
    {
        let newItem = NSMenuItem(
            title: string,
            action: selector,
            keyEquivalent: charCode
        )
        newItem.tag = Self.wantedTag
        return newItem
    }
    
    // If you use Storyboards, you have to individually set all the tags, so
    // its helpful to log untagged add/inserts so you can check they're not one
    // of your menu items you missed setting the tag for.
    private func logUntaggedAddInsert(
        _ item: @autoclosure () -> NSMenuItem,
        function: StaticString = #function)
    {
        #if DEBUG
        print("Call to \(function) for untagged NSMenuItem named \"\(item().title)\"")
        #endif
    }

    // MARK: Methods for your app to use
    // -------------------------------------
    public override func addItem(_ newItem: NSMenuItem)
    {
        guard newItem.tag == Self.wantedTag else
        {
            logUntaggedAddInsert(newItem)
            return
        }
        super.addItem(newItem)
    }
    
    // Replacement for addItem(withTitle:action:keyEquivalent)
    public func addTaggedItem(
        withTitle string: String,
        action selector: Selector?,
        keyEquivalent charCode: String) -> NSMenuItem
    {
        let newItem = makeTaggedItem(
            withTitle: string,
            action: selector,
            keyEquivalent: charCode
        )
        super.addItem(newItem)
        return newItem
    }
    
    public override func insertItem(_ newItem: NSMenuItem, at index: Int)
    {
        guard newItem.tag == Self.wantedTag else
        {
            logUntaggedAddInsert(newItem)
            return
        }
        super.insertItem(newItem, at: index)
    }

    // Replacement for insertItem(withTitle:action:keyEquivalent:at)
    public func insertTaggedItem(
        withTitle string: String,
        action selector: Selector?,
        keyEquivalent charCode: String,
        at index: Int) -> NSMenuItem
    {
        let newItem = makeTaggedItem(
            withTitle: string,
            action: selector,
            keyEquivalent: charCode
        )
        
        super.insertItem(newItem, at: index)
        return newItem
    }

    // MARK: Do NOT use these methods in your app
    // These will be used when macOS automatically inserts menus items.
    // -------------------------------------
    public override func addItem(
        withTitle string: String,
        action selector: Selector?,
        keyEquivalent charCode: String) -> NSMenuItem
    {
        let newItem = NSMenuItem(
            title: string,
            action: selector,
            keyEquivalent: charCode
        )
        logUntaggedAddInsert(newItem)
        return newItem
    }
    
    public override func insertItem(
        withTitle string: String,
        action selector: Selector?,
        keyEquivalent charCode: String,
        at index: Int) -> NSMenuItem
    {
        let newItem = NSMenuItem(
            title: string,
            action: selector,
            keyEquivalent: charCode
        )
        logUntaggedAddInsert(newItem)
        return newItem
    }
}

如果以编程方式创建菜单,您只创建TaggedItemMenu而不是NSMenu ,并确保您只使用addTaggedIteminsertTaggedItem创建菜单项。 这样,自动添加的菜单一开始就不会进入您的菜单,您以后也不必担心删除它们。

还请记住,当您添加子菜单时,这些子菜单基本上是包含在菜单项中的菜单。 子菜单的菜单部分也需要是一个TaggedItemMenu ,它包裹在里面的NSMenuItem需要被标记,否则不会被添加。 无论您是否需要标记菜单项,通过extension (或在本例中为TaggedItemMenu )向NSMenu添加addSubmenuinsertSubmenu ,为您进行包装是TaggedItemMenu用的。

如果您使用的是故事板,则必须确保在其“身份检查器” TaggedItemMenu每个菜单和子菜单的类更改为TaggedItemMenu

设置菜单类名称

并在其“属性检查器”中为每个菜单项单独设置标签

设置菜单项tag属性

在您开始计算菜单和子菜单中的所有项目之前,这似乎并不算太​​糟糕,所有这些都只是为了摆脱 Apple 决定注入您程序的几个项目。 当然,如果您稍后添加新菜单项,则需要确保设置它们的tag 这就是日志记录派上用场的原因。

如果您不能接受自动添加的菜单项,我建议您要么远离 Storyboard,要么在事后采取一种方法来删除这些项目,并接受它可能会在未来的某个 macOS 版本中崩溃。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM