Search code examples
swiftcocoaappkit

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


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.


Solution

  • 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
    }