6

I'm trying to get NSPopUpButton to render like a standard NSButton with only an image set, but not having any luck.

Much like the "+" button in Mail.app:

Not clicked Clicked

I assume they did this with NSPopUpButton. The obvious thing I've tried is:

NSMenuItem *imageItem = [[[NSMenuItem alloc] init] autorelease];
[imageItem setImage:[NSImage imageNamed:NSImageNameAddTemplate]];

[[popUpButton cell] setUsesItemFromMenu:NO];
[[popUpButton cell] setMenuItem:imageItem];
[[popUpButton cell] setImagePosition:NSImageOnly];

This doesn't show the image however, instead it just shows a pair of arrows (I suspect they're drawn over where the image would be). Calling [popUpButton setImage:...] also does nothing.

Is there a documented way to do this, or does it come down to some custom subclassing?

d11wtq
  • 34,788
  • 19
  • 120
  • 195

5 Answers5

4

To prevent the button from displaying the arrow:

[popupButton.cell setArrowPosition:NSPopUpNoArrow];
Tomer
  • 61
  • 3
3

Here is the code I used to finally get this working in Swift (modeled after Apple's Menu Madness demo app).

func setUpButton() {
    let popupButton = NSPopUpButton()
    popupButton.translatesAutoresizingMaskIntoConstraints = false
    popupButton.pullsDown = true
    popupButton.bordered = false
    let popupCell = popupButton.cell as! NSPopUpButtonCell
    popupCell.arrowPosition = NSPopUpArrowPosition.NoArrow
    popupButton.addItemWithTitle("")
    var item = popupButton.itemAtIndex(0)
    item?.image = NSImage(named: "add")
    item?.onStateImage = nil
    item?.mixedStateImage = nil
    popupButton.addItemWithTitle("Item1")
    item = popupButton.itemAtIndex(1)
    item?.action = #selector(item1Pressed)
    item?.target = self
    popupButton.addItemWithTitle("Item2")
    item = popupButton.itemAtIndex(2)
    item?.action = #selector(item2Tapped)
    item?.target = self
    self.addSubview(popupButton)

    // NOTE: These are auto layout helper methods I made that you won't have. 
    // Just note that here is where I set up the auto layout constraints.
    popupButton.widthConstraint(40)
    popupButton.heightConstraint(20)
    popupButton.centerVerticallyInSuperview()
    popupButton.trailingSpaceToSuperview(0)
}

// TO MAKE SURE ALL ITEMS ALWAYS VALID (WHAT I WANTED FOR MY USE CASE)
override func validateMenuItem(menuItem: NSMenuItem) -> Bool {
    return true
}

func item1Pressed() {
    // do stuff
}

func item2Pressed() {
    // do stuff
}

Be sure to make the width/height of the button big enough for the image. I found there was some padding on the right side of the button that covered my small image until I made the button wide enough to accommodate the mysterious padding.

Adam Johns
  • 35,397
  • 25
  • 123
  • 176
2

In your example, yes it is probably implemented with an NSPopUpButton, but rather than trying to customize the cell, what you really want is a button with -pullsDown: set to YES.

This is easiest to set up in Interface Builder. Even easier, use BWToolkit which features a button bar and custom buttons specifically for this purpose.

Mike Abdullah
  • 14,933
  • 2
  • 50
  • 75
  • Thanks, you're right, I do need `pullsDown`. What I was actually struggling with however was getting my image to display without displaying the arrows. The Menu Madness sample Laurent mentions has some great examples for little tricks I need to achieve. I'm learning a great deal from building this Cocoa app (which has turned into a much bigger task than I first thought). – d11wtq Dec 07 '10 at 23:44
1

@Laurent Etiemble's (now deleted) answer helped me and the OP.

Take a look at this thread and the Apple's sample Menu Madness: they contains some sample code to put an image on a NSPopUpButton.

phimuemue
  • 34,669
  • 9
  • 84
  • 115
0

In Xcode 4.4 you can do all this by using Interface Builder.

  1. drag the standard NSPopUpButton to your window,
  2. select the Style as whatever type of button you want,
  3. chose the button to have an image but don't set the image,
  4. drag an NSImage of whatever icon you want on top of the button.

I found that using the NSImage instead of setting the image of the button worked much better. Setting the button image caused problems when selecting items in the popup menu.

Vince
  • 525
  • 1
  • 3
  • 19
wigging
  • 8,492
  • 12
  • 75
  • 117