Re: Display selectd sub-menuItem in NSPopUpButton
Re: Display selectd sub-menuItem in NSPopUpButton
- Subject: Re: Display selectd sub-menuItem in NSPopUpButton
- From: John Joyce <email@hidden>
- Date: Sat, 15 Feb 2014 02:22:06 +0900
On Feb 15, 2014, at 12:29 AM, Keary Suska <email@hidden> wrote:
> On Feb 14, 2014, at 5:02 AM, Leonardo wrote:
>
>> I have filled my NSPopUpButton with menu and submenus.
>>
>> When I select a menuItem on the root menu (so, not a sub-menuItem), it
>> propery displays the menuItem selected. And when I re-click on the popUp
>> button, I get the selected menuItem under the mouse.
>>
>> But if I select a sub-menuItem, it doesn't display it. And if I re-click on
>> the popUp button, I don't get it under the mouse. Any time I click on the
>> button, I have to look for the selected item diving in the menu hierarchy.
>>
>> Any solution?
>
> I basic problem is that NSPopupButton does not support submenus. You can get the submenu item title to appear when the menu is dismissed but the side effect is that the item will be added to the top menu. I didn't go any further with that approach. It is too bad, because I would argue that there are good use cases for hierarchical menus in popup buttons.
>
> I don't have any real solutions, however, although I can suggest that you could "hide" the side effect with a "recents" section of the menu. Otherwise you will have to subclass NSPopupButtonCell and take over title and menu handling, AFAICT.
>
> HTH,
>
> Keary Suska
> Esoteritech, Inc.
> "Demystifying technology for your home or business"
>
I was intrigued so I had to do a test app.
This is doable.
Not pretty, but very doable and without any subclassing.
Basically, you can create this with NSMenuDelegate, swapping menus for NSPopUpButton using setMenu: and a little recursion to force the issue of selection (or state in NSMenuItem terms) and lastly a little NSNotificationCenter.
You’ll need a reference (property or ivar) to your NSPopUpButton, to an NSMenu that will only display the selection, and to the NSMenu that will be your flyout enabled menu (a menu with submenus). You will also need an NSMenuItem property or ivar that will both help you know what should be selected when you swap menus and what should be deselected when you next display your flyout menu.
Here’s a simple app delegate interface and implementation to show you.
@interface MyAppDelegate : NSObject <NSApplicationDelegate, NSMenuDelegate>
@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSPopUpButton *popUpButton;
@property (weak) IBOutlet NSMenu *selectionMenu;
@property (weak) IBOutlet NSMenu *flyOutMenu;
@property NSMenuItem *currentSelectedMenuItem;
@end
@implementation MyAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
[_popUpButton setMenu:_selectionMenu];
[self addSelector:@selector(selectSenderAndMakeSelectionMenuShowSender:) toAllMenuItemsInArray:_flyOutMenu.itemArray];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNSPopUpButtonWillPopUpNotification:) name:NSPopUpButtonWillPopUpNotification object:_popUpButton];
}
- (void)addSelector:(SEL)aSelector toAllMenuItemsInArray:(NSArray *)items {
for (NSMenuItem *aMenuItem in items) {
if (aMenuItem.hasSubmenu) {
[self addSelector:aSelector toAllMenuItemsInArray:aMenuItem.submenu.itemArray];
} else {
[aMenuItem setAction:aSelector];
}
}
}
- (IBAction)selectSenderAndMakeSelectionMenuShowSender:(id)sender {
NSMenuItem *selectedItem = (NSMenuItem *)sender;
if (_currentSelectedMenuItem != nil) {
if (![_currentSelectedMenuItem isEqualTo:selectedItem]) {
[_currentSelectedMenuItem setState:NSOffState];
}
}
[selectedItem setState:NSOnState];
[self setCurrentSelectedMenuItem:selectedItem];
[_selectionMenu removeAllItems];
[_selectionMenu addItem:selectedItem.copy];
}
- (IBAction)popUpButtonAction:(id)sender {
NSLog(@"[%@ %@: %@]", self, NSStringFromSelector(_cmd), sender);
NSMenuItem *selectedMenuItem = [_popUpButton selectedItem];
NSLog(@" selectedMenuItem=%@", selectedMenuItem);
}
- (void)menuWillOpen:(NSMenu *)menu {
NSLog(@"%@", NSStringFromSelector(_cmd));
if ([menu isEqualTo:_selectionMenu]) {
NSLog(@" %@", menu);
} else if ([menu isEqualTo:_flyOutMenu]) {
NSLog(@" %@", menu);
}
}
- (void)menuDidClose:(NSMenu *)menu {
[_popUpButton setMenu:_selectionMenu];
}
- (void)handleNSPopUpButtonWillPopUpNotification:(NSNotification *)aNotification {
[_popUpButton setMenu:_flyOutMenu];
[self makeSureOnlyCurrentSelectedItemIsSelectedInMenu:_flyOutMenu];
}
- (void)makeSureOnlyCurrentSelectedItemIsSelectedInMenu:(NSMenu *)aMenu {
for (NSMenuItem *aMenuItem in aMenu.itemArray) {
if (aMenuItem.hasSubmenu) {
[self makeSureOnlyCurrentSelectedItemIsSelectedInMenu:aMenuItem.submenu];
} else {
if ([aMenuItem isEqualTo:_currentSelectedMenuItem]) {
[aMenuItem setState:NSOnState];
} else {
[aMenuItem setState:NSOffState];
}
}
}
}
@end
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden