Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

BollywooD

macrumors 6502
Original poster
Apr 27, 2005
372
46
Hamburg
I am having trouble trying to update the values in an NSPopupButton programatically....

I can set it up just fine, in awakeFromNib, all the connections work as they should - I just can't redraw the items in the popupbutton.

Am I missing something?

I dropped an nspopupbutton into my project in xcode, connected it up to the cssButton Outlet.

heres my code:

my.h
Code:
@interface myPreferences : NSPreferencesModule <NSPreferencesModule>
{
	IBOutlet NSPopUpButton *CSSButton;
}
- (void)reloadCSSButton:(NSString *)cssName;
@property (retain) NSPopUpButton *CSSButton;

my.m
Code:
@implementation myPreferences

@synthesize CSSButton

- (void) awakeFromNib
{	
	//get User StyleSheet Name and load ccsButton
	NSString* cssFilePath = [[NSUserDefaults standardUserDefaults] stringForKey:styleSheetLocation];
	cssFilePath = [cssFilePath stringByExpandingTildeInPath];
	NSString* cssName = [cssFilePath lastPathComponent]; 
	
	[self reloadCSSButton:cssName];
}

//this works fine when called in awakeFromNib, but not elsewhere?
- (void)reloadCSSButton:(NSString *)cssName
{
	[CSSButton removeAllItems];
	if (cssName != nil) {
		[CSSButton addItemWithTitle:[NSString stringWithFormat:@"%@", cssName]];
		[[CSSButton menu] addItem:[NSMenuItem separatorItem]];
		[CSSButton addItemWithTitle:@"None Selected"];
		[CSSButton addItemWithTitle:@"Other..."];
		[CSSButton setAction: @selector(addCSS:)];
		[CSSButton selectItemAtIndex:0];
		[CSSButton setTarget:self];
	}
	else {
		[CSSButton addItemWithTitle:@"None Selected"];
		[CSSButton addItemWithTitle:@"Other..."];
		[CSSButton setAction: @selector(addCSS:)];
		[CSSButton selectItemAtIndex:0];
		[CSSButton setTarget:self];
	}

}

//this works fine
-(IBOutlet)addCSS:(id)sender
{
	if ([sender titleOfSelectedItem] == @"Other...")
	{
................unrelated code.....................
	}
	
	if ([sender titleOfSelectedItem] == @"None Selected")
	{
		[[NSUserDefaults standardUserDefaults] setValue:nil forKey:styleSheetLocation];
		[[NSUserDefaults standardUserDefaults] synchronize];
		
                //this call doesn't work, ie I am trying to redraw the popupbutton with out the separatorItem or the item:cssName......
		[self reloadCSSButton:nil];	
........... unrelated code.........................
	}
}

this is nuts....:confused:
 
This is what I would do, FWIW:

  • Set up the menu in IB as it will look, with "None Selected" and "Other"
  • Target each of those entries directly to specific separate IBAction methods (instead of using an if/else switch)
  • Give the first item a non-zero tag ( say, -1 )
  • Leave the lower part of the menu alone in your code

Use different methods for set or remove cssName (after all, only "None Selected" is the only routine that deletes the name).

In the method that sets cssName, do this:
Code:
NSMenu        *theMenu = [CSSButton menu];
NSMenuItem *newName;
if ( [[theMenu itemAtIndex:0] tag] == -1 ) {
    [theMenu insertItem:[NSMenuItem separatorItem] AtIndex:0];
    newName = [[NSMenuItem alloc] initWithTitle:cssName action:@selector( cssNameSelected: ) keyEquivalent:@""];
    [newName setTarget:self];
    [newName setTag:0];
    [theMenu insertItem:newName atIndex:0];
    [newName release]; // if you are not using garbage collection
} else {
    // cssName entry is already there, just change its title
    [[theMenu itemAtIndex:0] setTitle:cssName];
}
Remove the name thusly:
Code:
NSMenu    *theMenu = [CSSButton menu];
// this loop will just pass over if the top entry is "None Selected"
while ( [[theMenu itemAtIndex:0] tag] != -1 ) {
    // remove menu items until we hit the tagged item
    [theMenu removeItemAtIndex:0];
}

Style comment: Classes are usually capitalized, instance names are usually not
(Methods, BTW, are IBActions, not IBOutlets)
 
This is what I would do, FWIW:

Thanks for the feedback, I tried out your solution, but couldn't get that to add new items either....

either something's corrupted, or more likely, i'm missing something rather obvious.
 
In my application, I wanted to dynamically generate the items in a Popup Button. What I did to make a Popup Button work for me was to put a bogus item in the button in Interface Builder. Then in the awakeFromNib method, I have this code. The difference seems to be the removeAllItems method call. Maybe try that.

Code:
        [mode_select removeAllItems];
        [mode_select addItemWithTitle:@"Single"];
        [mode_select addItemWithTitle:@"Multi"];
        if (mandel_opencl_init(bytes, length) == EXIT_SUCCESS)
        {
                [mode_select addItemWithTitle:@"OpenCL"];
        }
        [mode_select selectItemAtIndex:1];
 
so I put some nslog()'s in:

Code:
NSLog(@"num: %d", [CSSButton numberOfItems]);
		NSLog(@"selected: %@", [CSSButton titleOfSelectedItem]);

and it looks as though the popupbutton is receiving all the calls.... the UI is just not updating.
 
Make sure your popup button is in a valid window on screen... since you're in Safari there could be some weird things going on.
 
Got it sorted, I removed my outlet in Interface Builder, and manually updated the button via its Control tag. now it works like a charm!
:D
 
If you are not concerned about <10.5 compatibilty, you might investigate using the NSMenu method -setHidden: on the first two menu items. Then all you have to do is change the title of the first item and never otherwise touch the menu.
 
I have another small issue,

I have the 3 items:
"cssFile"
"None selected"
"Other..."

when one selects "Other" an NSOpenPanel with an option to select a file opens up. However if I select "Cancel" for the selection, how can I re-select the item that was selected before hitting the "Other..." selection?

Is there a delegate call or something I can use to find the nsPopUpButton state before the "Other..." item was selected?
(does that make any sense....?)
:confused:
 
First:

The open panel should be a sheet to the window that owns the button. That way, the button will be inhibited by the sheet (it will consume all the window's events). Thus, you will not even need to change the menu state until you get the open panel's response.

If you can hide the item, as I suggested above, it would not matter, you could just reveal it (if you had already hidden it).

Apart from that, you can just put cssName's value in an ivar if you do need to recover it.

The other simple approach would be to make two menus, a short one and a long one, and swap which one the button is using.
 
Apart from that, you can just put cssName's value in an ivar if you do need to recover it.

too easy!
it took me all of 30 seconds to implement, once i knew what i wanted to do.

so simple, I didn't even think of it...

thanks for all your help
:D
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.