Выделение NSMenuItem с пользовательским представлением?
Я создал простой NSStatusBar
с NSMenu
, установленным в качестве меню. Я также добавил несколько NSMenuItems
в это меню, которые отлично работают (включая селекторы и выделение), но как только я добавляю пользовательский вид (setView:) не выделяется подсветка.
CustomMenuItem *menuItem = [[CustomMenuItem alloc] initWithTitle:@"" action:@selector(openPreferences:) keyEquivalent:@""];
[menuItem foo];
[menuItem setTarget:self];
[statusMenu insertItem:menuItem atIndex:0];
[menuItem release];
И мой метод foo:
- (void)foo {
NSView *view = [[NSView alloc] initWithFrame:CGRectMake(5, 10, 100, 20)];
[self setView:view];
}
Если я удалю метод setView, он выделит.
Я искал и искал и не могу найти способ реализации/включения этого.
Edit
Я реализовал выделение, выполнив код в этом вопросе в моем подклассе NSView:
Представление NSMenuItem (экземпляр подкласса NSView) не выделяется при наведении
#define menuItem ([self enclosingMenuItem])
- (void) drawRect: (NSRect) rect {
BOOL isHighlighted = [menuItem isHighlighted];
if (isHighlighted) {
[[NSColor selectedMenuItemColor] set];
[NSBezierPath fillRect:rect];
} else {
[super drawRect: rect];
}
}
Ответы
Ответ 1
Если вы добавляете представление в элемент меню, это представление должно рисовать выделение. Боюсь, это бесплатно. Из Темы программирования меню:
Элемент меню с видом не отображает его заголовок, состояние, шрифт или другие стандартные атрибуты чертежа и полностью назначает ответственность за оформление.
Ответ 2
Здесь приведена менее длинная версия выше. Это сработало для меня. (backgroundColour - ivar.)
- (void)drawRect:(NSRect)rect
{
if ([[self enclosingMenuItem] isHighlighted]) {
[[NSColor selectedMenuItemColor] set];
} else if (backgroundColour) {
[backgroundColour set];
}
NSRectFill(rect);
}
Ответ 3
Да, как упоминалось ранее, вы должны сделать это самостоятельно. Я использую AppKit NSDrawThreePartImage (...) для рисования, а также включает проверки, чтобы использовать внешний вид пользовательского элемента управления (синий или графитовый.) Чтобы получить изображения, я просто взял их с экрана (если кто-то знает лучший способ, добавьте комментарий.) Здесь часть моего MenuItemView drawRect:
// draw the highlight gradient
if ([[self menuItem] isHighlighted]) {
NSInteger tint = [[NSUserDefaults standardUserDefaults] integerForKey:@"AppleAquaColorVariant"];
NSImage *image = (AppleAquaColorGraphite == tint) ? menuItemFillGray : menuItemFillBlue;
NSDrawThreePartImage(dirtyRect, nil, image, nil, NO,
NSCompositeSourceOver, 1.0, [self isFlipped]);
}
else if ([self backgroundColor]) {
[[self backgroundColor] set];
NSRectFill(dirtyRect);
}
ИЗМЕНИТЬ
Должно быть определено следующее:
enum AppleAquaColorVariant {
AppleAquaColorBlue = 1,
AppleAquaColorGraphite = 6,
};
Они соответствуют двум вариантам внешнего вида в системных настройках. Кроме того, menuItemFillGray и menuItemFillBlue - это всего лишь NSImages стандартных градиентов заполнения пунктов меню.
Ответ 4
Обновление для 2019 года:
class CustomMenuItemView: NSView {
private var effectView: NSVisualEffectView
override init(frame: NSRect) {
effectView = NSVisualEffectView()
effectView.state = .active
effectView.material = .selection
effectView.isEmphasized = true
effectView.blendingMode = .behindWindow
super.init(frame: frame)
addSubview(effectView)
effectView.frame = bounds
}
required init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ dirtyRect: NSRect) {
effectView.isHidden = !(enclosingMenuItem?.isHighlighted ?? false)
}
}
Установите один из них в ваш menuItem.view
.
(Кредит принадлежит Сэму Соффсу, который помог мне разобраться в этом и прислал мне почти дословно этот код.)