Включение пунктов меню
По умолчанию каждый раз пользовательское событие происходит, NSMenu
автоматически включает и отключает каждый видимый пункт меню. Можно также вынудить меню обновить использование NSMenu
update
метод.
Существует два способа включить меню:
Автоматическое включение меню:
NSMenu
обновляет каждый пункт меню каждый раз, когда происходит пользовательское событие. Пункт меню включен еслиNSMenu
может найти надлежащий объект, реагирующий на действие пункта меню. Если Вы хотите, чтобы пункт меню остался отключенным даже при том, что объект реагирует на действие пункта меню, определите avalidateMenuItem:
метод для того объекта.Ручное Включение Меню: Вы используете
setEnabled:
включить или отключить каждый пункт меню индивидуально.
Для выбора системы использовать NSMenu
setAutoenablesItems:
с параметром YES
(для автоматического включения меню) или NO
(для ручного включения меню). Автоматическое включение меню идет по умолчанию.
Автоматическое включение меню
Когда Вы используете автоматическое включение меню, NSMenu
обновляет состояние каждого пункта меню каждый раз, когда происходит пользовательское событие. Обновить состояние пункта меню, NSMenu
сначала определяет цель элемента и затем определяет, реализует ли цель validateMenuItem:
или validateUserInterfaceItem:
(в том порядке). Более подробно:
Если цель пункта меню поставлена, то
NSMenu
первые проверки, которые будут видеть, реализует ли тот объект метод действия элемента. Если это не делает, то элемент отключен. Если цель действительно реализует метод действия элемента,NSMenu
первые проверки, которые будут видеть, реализует ли тот объектvalidateMenuItem:
илиvalidateUserInterfaceItem:
метод. Если это не делает, то пункт меню включен. Если это делает, то включенное состояние пункта меню определяется возвращаемым значением метода.Если цель пункта меню не поставлена (т.е. если это
nil
— обычно, если пункт меню подключен к Первому Респонденту), иNSMenu
объект не является контекстным меню, тогдаNSMenu
использует цепочку респондента (описанный в Цепочке Респондента) для определения цели. Если нет никакого объекта в цепочке респондента, реализующей действие элемента, элемент отключен.Если существует объект в цепочке респондента, реализующей действие элемента,
NSMenu
тогда проверки, чтобы видеть, реализует ли тот объектvalidateMenuItem:
илиvalidateUserInterfaceItem:
метод. Если это не делает, то пункт меню включен. Если это делает, то включенное состояние пункта меню определяется возвращаемым значением метода.Если цель пункта меню не поставлена и
NSMenu
объект является контекстным меню,NSMenu
проходит через те же шаги как прежде, но поисковый порядок на цепочку респондента отличается:Цепочка респондента для окна, в котором представление, инициировавшее контекстное меню, находится, начиная с представления.
Само окно.
Делегат окна.
NSApplication
объект.NSApplication
делегат объекта.
Реализация проверки
Как отмечено выше, прежде чем это будет выведено на экран, пункт меню проверяет, чтобы видеть, реализует ли его цель validateMenuItem:
или validateUserInterfaceItem:
. Если это делает, то включенное состояние пункта меню определяется возвращаемым значением метода. Можно поэтому условно включить или отключить пункт меню путем реализации любого из этих методов в цели меню (см. Выбор validateMenuItem: или validateUserInterfaceItem: определить, который является самым надлежащим). Стратегия реализации является тем же, какой бы ни Вы выбираете:
Чтобы решить, должен ли элемент быть включен, необходимо знать то, что он сделает, если пользователь выбирает его. Вы обычно сначала поэтому проверяете для наблюдения, какое действие связано с элементом (необходимо протестировать на каждое из действий, Вы интересуетесь).
При проверке действия, а не, скажем, заголовок удостоверяется что: (a) Ваш код работает с различными локализациями и устойчив против изменений в заголовке вследствие изменений в пользовательском интерфейсе и (b), Вы избегаете хрупкости необходимости не забыть использовать тот же тег для каждого элемента пользовательского интерфейса, вызывающего тот же метод на цель. (В случае
validateUserInterfaceItem:
, можно только проверить действие или тег.)Если действие - что-то, что Вы интересуетесь, то возвращаете булево значение, подходящее для текущего контекста.
Если действие не что-то, что Вы интересуетесь, то также:
Если Ваш суперкласс реализует метод проверки (например,
NSDocument
иNSObjectController
реализацияvalidateUserInterfaceItem:
, иNSObjectController
реализацииvalidateMenuItem:
), вызовите реализацию super; иначеВозвратите значение по умолчанию
YES
указать, что Вы обрабатываете метод проверки, даже если Вы не реализуете действие.
Следующий пример иллюстрирует реализацию validateUserInterfaceItem:
в подклассе NSDocument
.
- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem |
{ |
SEL theAction = [anItem action]; |
if (theAction == @selector(copy:)) { |
if ( /* there is a current selection and it is copyable */ ) |
{ |
return YES; |
} |
return NO; |
} |
else { |
if (theAction == @selector(paste:)) { |
if ( /* there is a something on the pasteboard we can use and |
the user interface is in a configuration in which it makes sense to paste */ ) { |
return YES; |
} |
return NO; |
} |
else { |
/* check for other relevant actions ... */ |
} |
} |
// Subclass of NSDocument, so invoke super's implementation |
return [super validateUserInterfaceItem:anItem]; |
} |
Выбор validateMenuItem: или validateUserInterfaceItem:
Обычно необходимо использовать validateUserInterfaceItem:
вместо validateMenuItem:
потому что прежний будет также работать на элементы панели инструментов, имеющие ту же цель и действие. Если, однако, существует дополнительная работа, которую Вы хотите выполнить, который является определенным для пункта меню, использовать validateMenuItem:
— например, validateMenuItem:
также хорошее место, чтобы переключить заголовки или установить состояние на пунктах меню, чтобы удостовериться, что они всегда корректны.
Вот пример использования validateUserInterfaceItem:
переопределять автоматическое включение. Если Ваше приложение имеет пункт меню Copy, отправляющий copy:
сообщение действия первому респонденту, тому пункту меню автоматически включают любое время объект, отвечающий на copy:
, такой как NSText
возразите, первый респондент ключевого или главного окна. При создании класса, экземпляры которого могли бы стать первым респондентом, и не поддерживающего копирование всего, что оно позволяет пользователю выбирать, необходимо реализовать validateUserInterfaceItem:
в том классе. validateUserInterfaceItem:
должен тогда возвратиться NO
если элементы, которые не могут быть скопированы, выбраны (или если никакие элементы не выбраны), и YES
если могут быть скопированы все элементы в выборе. Путем реализации validateUserInterfaceItem:
:, можно было отключить пункт меню Copy даже при том, что целевой объект действительно реализует copy:
метод. Если класс никогда не разрешает копировать, то Вы просто опускаете реализацию copy:
в том классе и пункте меню Copy отключен автоматически каждый раз, когда экземпляр того класса является первым респондентом.
Ручное включение меню
При использовании ручного включения меню Вы используете setEnabled:
включить или отключить каждый пункт меню индивидуально. Ни один из пунктов меню, даже те, которыми управляют классы Набора Приложения как NSTextView
, обновляются автоматически.
Для включения ручного включения меню использовать NSMenu
setAutoenablesItems:
с параметром NO
.