setEnabled NSMenuItem не работает, даже если для autoenablesItems установлено значение NO для NSMenu

Я поддерживаю некоторый устаревший код, и когда он был перенесен для компиляции с SDK 10.8, а не с SDK 10.7, некоторые эквивалентные сочетания клавиш для определенных пунктов меню перестали работать. Моя гипотеза заключается в том, что это связано с тем, что эти пункты меню находятся в отключенном состоянии. NSMenuItems, которые больше не работают, являются частью подменю, в котором для autoenablesItems было установлено значение NO (я подтвердил это в xib через инспектора атрибутов для этого подменю, а также программно, запросив [NSMenu autoenablesItems]. В основном это выглядит что вызов [NSMenuItem setEnabled:] не имеет никакого эффекта, потому что, если я запрашиваю [NSMenuItem isEnabled] сразу после вызова setEnabled:YES, состояние не изменилось, и он по-прежнему возвращает NO для isEnabled, Вот фрагмент кода с выводом он генерирует:

printf("DEBUG: Current state of menu item is ");
[nsMenuItem isEnabled] ? printf("enabled\n") : printf("DISABLED!\n");
printf("DEBUG: Current state of menu autoenablesItems is ");
[nsMenu autoenablesItems] ? printf("YES\n") : printf("NO\n");

[nsMenuItem setEnabled:YES];

printf("DEBUG: Current state of menu after setting it is ");
[nsMenuItem isEnabled] ? printf("enabled\n") : printf("DISABLED!\n");

Вывод:

DEBUG: Current state of menu item is DISABLED!
DEBUG: Current state of menu autoenablesItems is NO
DEBUG: Current state of menu after setting it is DISABLED!

Я также попытался создать подкласс NSMenuItem и переопределить setEnabled, чтобы увидеть, был ли другой вызов setEnabled, который перезаписывал мой вызов, но других вызовов, которые проходят через setEnabled, нет.

Если я нажму на родительское меню подменю, то, похоже, оно исправит состояние, и эти NSMenuItems будут включены, но мой код setEnabled не изменит это состояние. Я попытался добавить наблюдателя к подклассу, включенному, чтобы попытаться поймать, где состояние становится включенным при нажатии на родительское меню, но это также не дало никакого понимания, поскольку наблюдатель срабатывал только для моих вызовов setEnabled, которые на самом деле не меняют состояние.

Из того, что я могу сказать из документации Apple, setEnabled NSMenuItem должен работать, пока для autoenablesItems установлено значение NO в родительском меню, но в данном случае это не работает, и я не могу понять, почему.

В том же коде, если я использую SDK 10.7 для компиляции (предостережение: на самом деле это более старая версия базы кода, поэтому есть и другие отличия, но этот конкретный код тот же), я вижу, что вызов setEnabled изменяет состояние NSMenuItem. Когда он вводит этот код в сборке 10.7, NSMenuItem уже находится во включенном состоянии, но я попытался изменить вызов на setEnabled:NO, чтобы подтвердить, действительно ли это переключало состояние isEnabled, и это произошло, в отличие от сборки 10.8. .

Есть идеи, почему это не работает в 10.8? Я также пробовал с 10.9, и там тоже не получилось. Мне пока не удалось попробовать 10.10 или 10.11, так как есть какой-то другой код, который требует обновления, чтобы его можно было скомпилировать с более новыми SDK (опять же, это довольно старый устаревший код).


person user1176103    schedule 30.11.2015    source источник
comment
Когда эти журналы попадаются, вы уверены, что nsMenuItem на самом деле не равен нулю? Это приведет к тому, что NO будет напечатано для обоих журналов. Другим способом атаки может быть определение метода проверки меню для любого релевантного объекта (цель, первый ответивший) и проверка того, (1) он вызывается и (2) соблюдается ли его возвращаемое значение, даже когда автоматическое включение включено. выключенный. Происходит что-то подозрительное, потому что это старый код, который отлично работал в Cocoa много лет. Детективная работа - то, что нужно.   -  person bhaller    schedule 01.12.2015
comment
Я подтвердил, что nsMenu и nsMenuItem не равны нулю. Я также подтвердил, что после нажатия на элемент меню верхнего уровня (подменю которого nsMenu) в следующий раз после этого вызывается код, nsMenu и nsMenuItem остаются теми же объектами (тот же адрес в отладчике) , и isEnabled возвращает значение true. Цель в nsMenuItem равна нулю, но определено действие. Он имеет такое же состояние, когда он работает.   -  person user1176103    schedule 01.12.2015
comment
Когда ключевой эквивалент работает, мы оказываемся в коде определенного действия (через sendEvent NSApplication, за которым следует PerformSelector:withObject NSObject, за которым следует действие). Когда эквивалент ключа не работает, то из sendEvent NSApplication мы переходим к sendEvent NSWindow (сначала через sendEvent подкласса), за которым следует _reallySendEvent:isDelayedEvent: NSWindow, за которым следует keyDown: представления. Таким образом, действие никогда не вызывается, и я предполагаю, что это связано с тем, что пункт меню отключен.   -  person user1176103    schedule 01.12.2015
comment
Пункт меню фактически отключен в пользовательском интерфейсе? Отображается как серый текст и т. д.? Я не могу отделаться от мысли, что либо переменные nsMenu, либо переменные nsMenuItem не указывают на объекты, которыми вы их считаете, поэтому на самом деле вы манипулируете не теми объектами.   -  person Mark Bessey    schedule 01.12.2015
comment
Открытие меню в пользовательском интерфейсе приводит к изменению состояния — после нажатия на меню ярлыки работают, и пункт меню отображается как включенный. Это похоже на попытку определить, горит ли свет в холодильнике: открывая дверцу, вы меняете состояние, которое пытаетесь наблюдать. Есть ли другой способ, кроме визуального, чтобы увидеть, отключены ли пункты меню? Я предполагаю, что они отключены, поскольку эквивалент ключа не работает, и насколько я понимаю, эквиваленты ключа отключены, если пункт меню отключен. Я попробую программно изменить название, чтобы убедиться, что это тот же элемент.   -  person user1176103    schedule 03.12.2015


Ответы (2)


Не уверен, почему версия SDK имеет значение, но проверили ли вы меню в InterfaceBuilder, чтобы убедиться, что в нем не настроены привязки для состояния «включено»? Это был бы еще один способ загадочного отключения предметов.

В противном случае делегат меню может заменять элементы меню из другого кода или явно отключать элементы. Также есть метод NSMenuDelegate.

- menuHasKeyEquivalent:forEvent:target:action:

Который вызывается специально в тех случаях, когда была нажата клавиша быстрого доступа, и который может полностью обойти включенное/отключенное состояние пунктов меню.

person Mark Bessey    schedule 01.12.2015
comment
Чтобы проверить привязки, вы смотрите на Инспектора привязок? Если это так, я не вижу ни в одном из разделов отметки Bind to. Также в базе кода нет экземпляра menuHasKeyEquivalent, поэтому я не думаю, что это может быть проблемой. - person user1176103; 01.12.2015
comment
Странный. Я могу убедиться, что с SDK 10.10 и 10.11 и тривиальной тестовой программой все работает так, как вы ожидаете — если autoEnablesItems отключен для меню, setEnabled и isEnabled работают и возвращают правильный результат. - person Mark Bessey; 01.12.2015
comment
Чтобы ответить на другой вопрос - да, загляните в Инспектор привязок, после выбора пункта меню. - person Mark Bessey; 02.12.2015

просто используйте это для включения/отключения пунктов меню

NSMenu *menu = [[NSMenu alloc] init];

добавить пункт меню отключения

[menu addItemWithTitle:@"DisableItem" action:nil keyEquivalent:@""];

добавить пункт меню включения

[menu addItemWithTitle:@"EnableItem" action:@selector(method:) keyEquivalent:@""];
person ERbittuu    schedule 02.12.2015