I would like an NSPopUpButton to display a different title than the title of the menu item that is selected.
Suppose I have an NSPopUpButton that lets the user pick a list of currencies, how can I have the collapsed/closed button show only the currencies abbreviation instead of the menu title of the selected currency (which is the full name of the currency)?
I imagine I can override draw in a subclass (of NSPopUpButtonCell) and draw the entire button myself, but I would prefer a more lightweight approach for now that reuses the system's appearance.
The menu items have the necessary information about the abbreviations, so that's not part of the question.
Subclass NSPopUpButtonCell, override drawTitle(_:withFrame:in:) and call super with the title you want.
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)
}
In the same way you can override intrinsicContentSize in a subclass of NSPopUpButton. Replace the menu, call super and put the original menu back.
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
}
Ok, so I found out how I can modify the title. I create a cell subclass where I override setting the title based on the selected item. In my case I check the represented object as discussed in the question.
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 {}
}
}
Then in my button subclass I set the cell (I use 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
}
A downside though is that I have to copy over all attributes of the cell I configured in Interface Builder. I can of course just set the cell class in Interface Builder, which makes this superfluous.
One thing I haven't figured out yet is how I can have the button have the correct intrinsic content size now. It still tries to be as wide as the longest regular title.
And the second thing I haven't figured out is how to make this work with bindings. If the buttons content is provided via Cocoa Bindings then I can only bind the contentValues, and the cell's title property is never called.
来源:https://stackoverflow.com/questions/48935340/how-do-i-change-modify-the-displayed-title-of-an-nspopupbutton