NSPopupButton madness.

Discussion in 'Mac Programming' started by BollywooD, Apr 18, 2010.

  1. macrumors 6502

    Joined:
    Apr 27, 2005
    Location:
    Surfers Paradise
    #1
    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:
     
  2. macrumors 68000

    Sydde

    Joined:
    Aug 17, 2009
    #2
    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)
     
  3. thread starter macrumors 6502

    Joined:
    Apr 27, 2005
    Location:
    Surfers Paradise
    #3
    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.
     
  4. macrumors 68000

    Sydde

    Joined:
    Aug 17, 2009
  5. macrumors 6502a

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #5
    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];
     
  6. thread starter macrumors 6502

    Joined:
    Apr 27, 2005
    Location:
    Surfers Paradise
    #6
    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.
     
  7. macrumors 68000

    Sydde

    Joined:
    Aug 17, 2009
    #7
    Then can you force it with something like [CSSButton display]?
     
  8. thread starter macrumors 6502

    Joined:
    Apr 27, 2005
    Location:
    Surfers Paradise
    #8
    I tried that too....
    :confused:
     
  9. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #9
    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.
     
  10. thread starter macrumors 6502

    Joined:
    Apr 27, 2005
    Location:
    Surfers Paradise
    #10
    thats what I was thinking too.
    i'll look into it...

    thanks for all the ideas.:eek:
     
  11. thread starter macrumors 6502

    Joined:
    Apr 27, 2005
    Location:
    Surfers Paradise
    #11
    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
     
  12. macrumors 68000

    Sydde

    Joined:
    Aug 17, 2009
    #12
    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.
     
  13. thread starter macrumors 6502

    Joined:
    Apr 27, 2005
    Location:
    Surfers Paradise
    #13
    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:
     
  14. macrumors 68000

    Sydde

    Joined:
    Aug 17, 2009
    #14
    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.
     
  15. thread starter macrumors 6502

    Joined:
    Apr 27, 2005
    Location:
    Surfers Paradise
    #15
    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
     

Share This Page