Разделительный элемент в NSPopupButton с привязками
Содержание NSPopupButton
связаны с NSArray
струн.
Как мы можем вставить разделитель через привязки?
"-
"Струны (как в старые / классические дни) не работают, то есть появляются буквально как"-
" пункт меню.
Есть ли готовое решение со стандартными классами Какао и привязками?
Это должно быть тривиальной проблемой, но я не могу найти решение проблемы, которая не включает в себя глупые хаки, такие как создание подклассов NSMenu
, NSPopupButton
или другие не интуитивные обходные пути.
5 ответов
Я не мог найти чистый способ динамически добавлять разделители в меню при использовании привязок. Самый простой (и наиболее многократно используемый) способ, который я нашел, - это использовать NSMenuDelegate для динамического обмена NSMenuItems с определенным названием, таким как @"---"
с разделителями элементов в menuNeedsUpdate:
метод делегата.
Шаг 1. Создайте объект NSO, соответствующий протоколу NSMenuDelegate.
#import <Cocoa/Cocoa.h>
@interface SeparatorMenuDelegate : NSObject <NSMenuDelegate>
@end
@implementation SeparatorMenuDelegate
-(void)menuNeedsUpdate:(NSMenu *)menu {
NSArray* fakeSeparators = [[menu itemArray] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"title == '---'"]];
for (NSMenuItem* fakeSep in fakeSeparators) {
[menu insertItem:[NSMenuItem separatorItem] atIndex:[menu indexOfItem:fakeSep]];
[menu removeItem:fakeSep];
}
}
@end
Шаг 2: Связать вещи в Интерфейсном Разработчике.
Перетащите Объект в сцену, которая содержит экземпляр NSPopupButton.
Установите класс объекта в SeparatorMenuDelegate
Twirl откройте элемент управления NSPopupButton в Outline документа и выберите меню внутри него. Затем установите делегата для меню на SeparatorMenuDelegate
объект, который вы втащили ранее.
После этого все элементы в меню с заголовком @"---" будут преобразованы в элементы-разделители.
Если у вас есть несколько экземпляров NSPopupButton в одной и той же сцене, вы можете установить делегат их Меню на один и тот же объект (вам нужен только один SeparatorMenuDelegate
за сцену).
ИМХО, самое чистое решение по-прежнему заключается в создании подклассов NSMenu - этот вид настройки - именно то, для чего предназначен подкласс. Следующее решение основано на том, что @matt написал много лет назад на Cocoabuilder, и обновлено, чтобы стать более универсальным, в том числе на High Sierra.
Сначала определите "волшебную строку" для представления элемента-разделителя в вашем коде; сделайте это в заголовочном файле, который будут импортированы всеми затронутыми классами. В этом примере я выбрал "---", но, конечно, это может быть любая строка, которая вам нравится:
#define MY_MENU_SEPARATOR @"---"
Во-вторых, создайте подкласс NSMenu и перезапишите два метода, которые добавляют пункты меню, для обработки специального случая разделителя:
@implementation MyMenu
- (NSMenuItem*)addItemWithTitle:(NSString*)aString action:(SEL)aSelector keyEquivalent:(NSString*)keyEquiv
{
if ([aString isEqualToString:MY_MENU_SEPARATOR])
{
NSMenuItem *separator = [NSMenuItem separatorItem];
[self addItem:separator];
return separator;
}
return [super addItemWithTitle:aString action:aSelector keyEquivalent:keyEquiv];
}
- (NSMenuItem*)insertItemWithTitle:(NSString*)aString action:(SEL)aSelector keyEquivalent:(NSString*)keyEquiv atIndex:(NSInteger)index
{
if ([aString isEqualToString:MY_MENU_SEPARATOR])
{
NSMenuItem *separator = [NSMenuItem separatorItem];
[self insertItem:separator atIndex:index];
return separator;
}
return [super insertItemWithTitle:aString action:aSelector keyEquivalent:keyEquiv atIndex:index];
}
@end
И это все. Задайте для затронутых меню класс MyMenu в Инспекторе удостоверений Интерфейсного Разработчика, и они будут вставлять элементы разделителя, где это необходимо. Работает как для меню, так и для всплывающих окон.
Вот ответ n.Drake в Swift 3.1:
class MySeparatorMenuDelegate : NSObject, NSMenuDelegate {
func menuNeedsUpdate(_ menu: NSMenu) {
for (ix,mi) in menu.items.enumerated() {
if mi.title == "---" {
menu.removeItem(at: ix)
menu.insertItem(NSMenuItem.separator(), at: ix)
}
}
}
}
Посмотрите на документацию для NSContentPlacementTagBindingOption
, добавлено в Mac OS X 10.5. В инспекторе привязок Интерфейсного Разработчика это доступно для таких элементов, как кнопки всплывающего меню; перейдите в раздел "Выбор значений" и найдите в любой категории контента (контент, объекты контента, значения контента) "Тег размещения контента". Значением поля должно быть число, соответствующее номеру тега какого-либо пункта меню.
Содержимое связанного массива будет вставлено в меню вместо того элемента, который имеет указанное значение тега. В этом случае статическое меню будет содержать ваш разделитель и, по крайней мере, еще один элемент, чтобы указать, куда идут значения массива.