如何 change/modify NSPopUpButton 的显示标题

How do I change/modify the displayed title of an NSPopUpButton

我希望 NSPopUpButton 显示与所选菜单项标题不同的标题。

假设我有一个 NSPopUpButton 让用户选择货币列表,我怎样才能让 collapsed/closed 按钮只显示货币缩写而不是所选货币的菜单标题 (这是货币的全称)?

我想我可以重写子类(NSPopUpButtonCell)中的绘制并自己绘制整个按钮,但我现在更喜欢重用系统外观的更轻量级的方法。

菜单项包含有关缩写的必要信息,因此这不是问题的一部分。

好的,所以我找到了如何修改标题。我创建了一个单元格 subclass ,我在其中覆盖了基于所选项目的标题设置。在我的例子中,我检查了问题中讨论的代表 object。

final class MyPopUpButtonCell: NSPopUpButtonCell {
override var title: String! {
    get {
       guard let selectedCurrency = selectedItem?.representedObject as? ISO4217.Currency else {
           return selectedItem?.title ?? ""
       }
           return selectedCurrency.rawValue
       }
       set {}
    }
}

然后在我的按钮 subclass 我设置单元格(我使用 xibs)

override func awakeFromNib() {
    guard let oldCell = cell as? NSPopUpButtonCell else { return }
    let newCell = MyPopUpButtonCell()
    newCell.menu = oldCell.menu
    newCell.bezelStyle = oldCell.bezelStyle
    newCell.controlSize = oldCell.controlSize
    newCell.autoenablesItems = oldCell.autoenablesItems
    newCell.font = oldCell.font
    cell = newCell
}

缺点是我必须复制我在 Interface Builder 中配置的单元格的所有属性。 我当然可以只设置单元格 class Interface Builder,这使它变得多余。

我还没有弄清楚的一件事 是我现在如何让按钮具有正确的固有内容大小。它仍然尝试与最长的常规标题一样宽。

我还没有弄清楚的第二件事 是如何使它与绑定一起工作。如果按钮内容是通过 Cocoa 绑定提供的,那么我只能绑定 contentValues,并且永远不会调用单元格的标题 属性。

子类 NSPopUpButtonCell,覆盖 drawTitle(_:withFrame:in:) 并使用您想要的标题调用 super

override func drawTitle(_ title: NSAttributedString, withFrame frame: NSRect, in controlView: NSView) -> NSRect {
    var attributedTitle = title
    if let popUpButton = self.controlView as? NSPopUpButton {
        if let object = popUpButton.selectedItem?.representedObject as? Dictionary<String, String> {
            if let shortTitle = object["shortTitle"] {
                attributedTitle = NSAttributedString(string:shortTitle, attributes:title.attributes(at:0, effectiveRange:nil))
            }
        }
    }
    return super.drawTitle(attributedTitle, withFrame:frame, in:controlView)
}

以同样的方式,您可以在 NSPopUpButton 的子类中覆盖 intrinsicContentSize。替换菜单,调用super,把原来的菜单放回去。

override var intrinsicContentSize: NSSize {
    if let popUpButtonCell = self.cell {
        if let orgMenu = popUpButtonCell.menu {
            let menu = NSMenu(title: "")
            for item in orgMenu.items {
                if let object = item.representedObject as? Dictionary<String, String> {
                    if let shortTitle = object["shortTitle"] {
                        menu.addItem(withTitle: shortTitle, action: nil, keyEquivalent: "")
                    }
                }
            }
            popUpButtonCell.menu = menu
            let size = super.intrinsicContentSize
            popUpButtonCell.menu = orgMenu
            return size
        }
    }
    return super.intrinsicContentSize
}