Swift: 如何更改 NSPopupButton 编辑菜单项文本

Swift: How to change NSPopupButton edit menu item text

我的 GUI 上有一个 NSPopupButton,我正在寻找一种方法来以编程方式更改特定项目的文本:

'item 1'
'item 2' ---> 'item b'
'item 3'

您问题的直接答案是,您可以通过 NSPopUpButtonmenu 属性 访问这些项目,然后是 items 属性在出现的菜单上。但是请不要在这里停止阅读,因为我不会那样做。

您想要更改菜单项的原因很可能是为了反映模型中某物的状态。也许标题是 context-sensitive 并且应该根据当前选择或类似的东西而改变。您通常可以在根本不需要 NSPopUpButton 的出口的情况下执行此操作,只需在菜单项目标的 validateMenuItem 方法中执行即可:

override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
    if menuItem.action == #selector(someAction:) {
        if self.someCondition {
            menuItem.title = "Foo"
        } else {
            menuItem.title = "Bar"
        }
    }

    return super.validateMenuItem(menuItem)
}

这不仅可以简化您的设计并降低程序逻辑需要了解您的 UI 设置的程度,而且更加灵活,因为它适用于任何菜单项指向相同的目标和行动。如果您决定将菜单项移出 pop-up 按钮并移至标准菜单栏、toolbar-based 菜单或其他内容,或者如果您希望在其中几个位置有多个菜单项, 它们的工作方式完全相同,您无需编写任何新代码。

我有时使用的另一个技巧是通过 Cocoa 绑定填充菜单项的标题。这也具有将 UI 与界面分离的效果,但它是一个您可能还不想跳入的主题的更高级的部分。

编辑:既然我知道了你的用例,那正是我倾向于使用 Cocoa 绑定的那种东西 :-) 比如:

class MyViewController: NSViewController {
    ...

    // make these @objc and dynamic so that they are KVC-compliant
    @objc dynamic var password: String
    @objc dynamic var bits: Int

    // register our password strength as dependent on 'password' and 'bits'
    @objc private static let keyPathsForValuesAffectingPasswordStrength: Set<String> = [
        #keyPath(password),
        #keyPath(bits)
    ]

    @objc var passwordStrength: String {
        // obviously you'll do a better test than this in real life ;-)
        if self.password.count >= 8 {
            return NSLocalizedString("Strong", comment: "Strong")
        } else {
            return NSLocalizedString("Weak", comment: "Weak")
        }
    }

    ...
}

基本上,这里发生的事情是:

  • 一切都是@objc因为CocoaBindings是用Objective-C写的,需要能够看到我们的属性

  • dynamic 添加到 passwordbits 属性允许 Cocoa 将魔法粘贴到访问器中,使它们在属性时触发通知改变。

  • keyPathsForValuesAffectingPasswordStrength 属性 告诉 Cocoa 当为 passwordbits 触发通知时,它们也应该触发passwordStrength.

现在,我们只需转到 Interface Builder,并将我们的安全密码字段绑定到 password 属性,如下所示:

然后,我们将滑块绑定到 bits 属性,如下所示:

对于我们的标签,我们变得更奇特一些,并设置了一个包含 passwordStrengthbits 的模式:

因此,除了一些 属性 定义外,几乎没有任何代码,我们得到:

很漂亮,嗯?