Reputation: 642
I have a list of elements which needs to be displayed in a NSPopUpButton. I want the PopUp button to display the list in alphabetically sorted order. Moreover, there is a NEW MenuItem in the list which would pick up a string from a text field and insert it into the PopUp button. So, there are two questions I would like to ask:
Upvotes: 4
Views: 1610
Reputation: 642
I've managed to sort the popup button using the following bindings:
[arrayController bind:@"contentArray" toObject:self withKeyPath:@"displayElements" options:nil];
[popUpButton bind:@"content" toObject:arrayController withKeyPath:@"arrangedObjects" options:nil];
[popUpButton bind:@"contentValues" toObject:arrayController withKeyPath:@"arrangedObjects.title" options:nil];
Also I have changed the statement in init from:
displayElements = [[NSMutableArray alloc] initWithObjects:@"one",@"two",@"three", nil];
to
displayElements = [[NSMutableArray alloc] initWithObjects:[[NSMenuItem alloc]initWithTitle:@"one" action:nil keyEquivalent:@""],
[[NSMenuItem alloc]initWithTitle:@"two" action:nil keyEquivalent:@""],
[[NSMenuItem alloc]initWithTitle:@"three" action:nil keyEquivalent:@""],
nil];
and the sorting is working just fine.
Now the issue is that if I add a Sub-Menu to any of the menu Items and after that I add a new NSMenuItem to the array controller, the Sub-Menu Previously added disappears as shown in images below:
Before adding New Item:
After adding a new Item:
The Same behavior is being displayed when we sort the elements.
Any ideas on fixing this problem??
Upvotes: 1
Reputation: 18253
If you use an NSArrayController
to populate the popup button (or rather, its menu), then you can just define a sort descriptor to handle the sorting.
Getting an array controller to work with a popup button the first time can be a little tricky, but if you bind the popup button's contents to the array controller's arrangedObjects
and then bind the content values to a suitable string property of your model objects, you should be fine.
Then, adding a new item will just be a matter of adding an item through the array controller.
So, in case you are not familiar with the NSArrayController
class and bindings, the following is short description of how you can do it in Interface Builder. Assume your elements have a string property called name
.
arrangedObjects
controller key. This is the default option for that binding.arrangedObjects
controller key and name
model key path. This will give the right text in the menu.setSortDescriptors:
method). To do this, you might want to define an outlet on the file's owner to hold array controller.add:
method.This should get you going with a minimum of your own code, and a little bit of Interface Builder magic.
For fairly straightforward UI elements, bindings can really save a lot of work. More about them here.
Edited to add an example:
For an example of how this can be done, consider an app with an app delegate that has a data
property, an array of dictionaries, with a name
property. Notice that this is one level of abstraction deeper than your example, in which the array only holds single strings. Personally, I prefer it that way.
self.data = [NSMutableArray arrayWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:@"Flowers", @"name", nil],
[NSDictionary dictionaryWithObjectsAndKeys:@"Animals", @"name", nil],
[NSDictionary dictionaryWithObjectsAndKeys:@"Trees", @"name", nil],
nil];
// Sort the array controller alphabetically by the name property
NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
self.arrayController.sortDescriptors = [NSArray arrayWithObject:sd];
Upvotes: 2
Reputation: 642
Thanks for the answer @Monolo
I have been able to load the values (which have been stored in NSMutableArray) in the popup from NSArrayController. But I am still stuck with the sorting thing. Below is the code, I am not being able to figure what is wrong with it.
ControllerClass.h
@interface ControllerClass : NSObject{
NSWindow *window;
NSArray *sortDescriptorArray;
NSMutableArray *displayElements;
NSSortDescriptor *sortDescriptor;
IBOutlet NSArrayController *arrayController;
IBOutlet NSTextField *newItemTextField;
}
@property (readwrite,retain) NSMutableArray *displayElements;
-(id)init;
-(IBAction)AddItem:(id)sender;
@end
============================================================
ControllerClass.m
#import "ControllerClass.h"
@implementation ControllerClass
@synthesize displayElements;
-(id)init
{
self =[super init];
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"displayElements" ascending:YES];
sortDescriptorArray = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[arrayController setSortDescriptors:sortDescriptorArray];
displayElements = [[NSMutableArray alloc] initWithObjects:@"one",@"two",@"three", nil];
return self;
}
-(IBAction)AddItem:(id)sender
{
[arrayController addObject:[newItemTextField stringValue]];
}
@end
Upvotes: 0