PDA

View Full Version : validateMenuItem ?




Darkroom
Jun 23, 2008, 02:40 AM
how am i suppose to choose which of the menu items i want to address in a function like this? the following function enables or disables all menu items that are present...


- (BOOL)validateMenuItem:(NSMenuItem *)item
{
if ([mainWindow isVisible])
return NO;
else
return YES;
}


i've searching for hours and it seems that something simple like disabling a menu item should be easier than it is... a simple void function something like this would be great, but it won't work... won't it?


-(void)disableThisItem
{
if ([mainWimdow isVisible] && [itemWithTitle:@"Make Window Visible" isEnabled])
{
[disable itemWithTitle:@"Make Window Visible"]
}
}



robbieduncan
Jun 23, 2008, 04:19 AM
validateMenuItem: will be called for EVERY menu item as required. You can assign your menu items numeric IDs in interface builder and then tell which menu item is being queried when the method is called.

Darkroom
Jun 23, 2008, 04:28 AM
validateMenuItem: will be called for EVERY menu item as required. You can assign your menu items numeric IDs in interface builder and then tell which menu item is being queried when the method is called.

for numeric IDs do you mean the "Object ID" under Identity, or "Tag" under Attributes? can you post a small code example?

the documentation lists actions or tags act to determine which menu item is targeted. so in IB i wrote "Tag: 1" under Attributes for my menu item and included the following code:


- (BOOL)validateMenuItem:(NSMenuItem *)item
{
if (([item tag] == 1) && ([mainWindow isVisible]))
return NO;
else
return YES;
}


but it still isn't working...

robbieduncan
Jun 23, 2008, 04:40 AM
for numeric IDs do you mean the "Object ID" under Identity, or "Tag" under Attributes? can you post a small code example?

Tag. You should be able to recover the tag of the item being validated with

[item tag]

so your method should looks something like

- (BOOL)validateMenuItem:(NSMenuItem *)item
{
int tag = [item tag];
if (tag==<tag for the item>)
{
if ([mainWindow isVisible])
return NO;
else
return YES;
}
}


So you are probably thinking why is this method used and not the one I suggested? This method is better as it only validates the item on demand. With your method we'd waste cycles all over the place updating menu items and them updating them again without the item ever being shown. And as tags are independent of the actual menu title this will survive localisation unlike your itemWithTitle:

Darkroom
Jun 23, 2008, 04:43 AM
oh nevermind... it seems to be working now! yaaaa :)

Darkroom
Jun 23, 2008, 04:49 AM
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
int tag = [item tag];
if (tag==<tag for the item>)
{
if ([mainWindow isVisible])
return NO;
else
return YES;
}
}


and i'm gonna use this because it's better... thanks...

So you are probably thinking why is this method used and not the one I suggested? This method is better as it only validates the item on demand. With your method we'd waste cycles all over the place updating menu items and them updating them again without the item ever being shown. And as tags are independent of the actual menu title this will survive localisation unlike your itemWithTitle:

i don't really get it... but i believe you nonetheless :D

i mean, isn't the function validateMenuItem going to always get called, or catalogued, or cycled... whatever... so why is it important to use a tag that is independent than the item's title? aren't they both acting as pointers to the menu item object? so how is the tag independent and the title not?

robbieduncan
Jun 23, 2008, 04:54 AM
i don't really get it... but i believe you nonetheless :D

Well lets imagine we had a menu item that needed to have it's status updated everytime the user did anything (like the title of the undo item which should read Undo "<Action>"). If we updated this every time the user did anything we might end up updating it every second or faster. But the user only actually displays that menu once ever 10 minutes or so as they know the keyboard shortcuts.

So if we used your idea of a disableThisItem method (suitably renamed for the undo item) we'd have updated the menu item 600 times before the user actually wanted to see it. validateMenuItem: only gets called when the user actually displays the menu so we'd update the item exactly once saving 599 updates and a load of CPU.

so why is it important to use a tag that is independent than the item's title? aren't they both acting as pointers to the menu item object? so how is the tag independent and the title not?

Neither are pointers to the menu item object, rather both are properties of the menu item object. To find a menu item by either tag or title we have to search the menu objects checking that property. So why have 2 properties? Tag is not displayed to the user and will always be the tag you set it. Title is displayed to the user. So if you have English, French, German... localisations for your application the title actually displayed could be different that the English one. So searching by title is not a good idea.

Darkroom
Jun 23, 2008, 05:03 AM
Well lets imagine we had a menu item that needed to have it's status updated everytime the user did anything (like the title of the undo item which should read Undo "<Action>"). If we updated this every time the user did anything we might end up updating it every second or faster. But the user only actually displays that menu once ever 10 minutes or so as they know the keyboard shortcuts.

So if we used your idea of a disableThisItem method (suitably renamed for the undo item) we'd have updated the menu item 600 times before the user actually wanted to see it. validateMenuItem: only gets called when the user actually displays the menu so we'd update the item exactly once saving 599 updates and a load of CPU.



Neither are pointers to the menu item object, rather both are properties of the menu item object. To find a menu item by either tag or title we have to search the menu objects checking that property. So why have 2 properties? Tag is not displayed to the user and will always be the tag you set it. Title is displayed to the user. So if you have English, French, German... localisations for your application the title actually displayed could be different that the English one. So searching by title is not a good idea.

oohhhh ok! surprisingly i totally get it... total n00b here... thanks for the explanation... using tag makes perfect sense...

Darkroom
Jun 23, 2008, 07:09 AM
ok... so i have the tags understood, but the action part not so much... i believe i'm following the documentation correctly concerning the action side of validateMenuItem, but it's not working.


- (IBAction)selectWhite:(id)sender
{
setTarget:myWhiteSelection;
[myWhiteSelection changeWhite:nil];
}

- (BOOL)validateMenuItem:(NSMenuItem *)item
{
if ([item action] == @selector(selectWhite:))
return NO;
return YES;
}


my IBAction works, but it seems that when i associate the menu items (Menu Bar Item + Dock Menu Item) to that action thru the validateMenuItem function, they do not become disabled when the NSView turns white, or after the IBAction is executed.

robbieduncan
Jun 23, 2008, 07:15 AM
I've never tried doing that, but it should work if the items action really is set to selectWhite:

Some of that code doesn't look legal to me: setTarget:myWhiteSelection;???

Darkroom
Jun 23, 2008, 07:28 AM
I've never tried doing that, but it should work if the items action really is set to selectWhite:

Some of that code doesn't look legal to me: setTarget:myWhiteSelection;???

yeah, my code is all crazy... a lot of it is sniped months ago when i had been awake for 24+ hours, so some of it is hazy - setTarget:myWhiteSelection is calling another IBAction from another class... probably not at all stylish, but it works...

to find out if it's the IBAction function that was causing it not to work, i had just changed my working tag methods to an action method in my other validateMenuItem function and it's giving me the same flawed results. when i use the action method, not only does it not disable the menu item, but the menu item is disabled from launch of the app...

one thing i noticed from the documentation is that the @selector(action) doesn't have a ":" after the action's name... originally i also omitted the ":" but nothing was being called. adding the ":" gives me crazy results... is the action the IBAction? or is there another action that the documentation is referring to?

robbieduncan
Jun 23, 2008, 07:33 AM
If it's disabled when the application launches then either:

1) It's being disabled by a validateMenuItem: function somewhere
2) It's target or action are invalid/don't exist.

With reference to the illegal code I mean you have "setTarget:myWhiteSelection;" as a statement on it's own. This looks like an message missing it's target and square brackets...

Darkroom
Jun 23, 2008, 07:53 AM
If it's disabled when the application launches then either:

1) It's being disabled by a validateMenuItem: function somewhere
2) It's target or action are invalid/don't exist.

With reference to the illegal code I mean you have "setTarget:myWhiteSelection;" as a statement on it's own. This looks like an message missing it's target and square brackets...

i commented out setTarget:myWhiteSelection and it still does what it's suppose to do, so that was probably some junk just laying around.

i'm certain that it's not being disabled by another validateMenuItem somewhere, and the menu item is wired up to the "selectWhite" action in IB... i'm still curious about the ":" not being present at the end of the action according to the documentation...