NSSlider управления стрелками на NSMenu для NSStatusItem- Objective-C/ Какао
Я хотел бы создать элемент состояния с вертикальным ползунком в нем, очень похоже на управление звуком, предоставляемое Apple. У меня вопрос: как мне заставить его реагировать на клавиши со стрелками вверх / вниз, как слайдер в меню звука?
Я попытался создать подкласс NSSlider, который бы увеличивал / уменьшал его значение при нажатии клавиш (см. Ниже), но мне нужно сделать его первым респондентом. Чтобы сделать его первым респондентом, я сделал основной класс делегатом этого меню и добавил этот метод:
- (void)menuWillOpen: (NSMenu*)menu
{
if (menu == statusBarMenu) {
[THE_WINDOW_THAT_CONTAINS_THE_SLIDER makeFirstResponder: slider];
}
В какое окно мне звонить? Должен ли я сделать это по-другому? Как бы вы это сделали?
Подкласс слайдера:
#import <AppKit/AppKit.h>
@interface KeyRespondingSlider : NSSlider
@end
@implementation KeyRespondingSlider
- (BOOL)canBecomeKeyView
{
return YES;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (void)keyDown: (NSEvent*)theEvent
{
unsigned short keyCode = [theEvent keyCode];
if (keyCode == 126) { // up-arrow
[self setDoubleValue: [self doubleValue] + kChange];
}
else if (keyCode == 125) { // down-arrow
[self setDoubleValue: [self doubleValue] - kChange];
}
}
@end
Я проверил это, и он работает, когда это первый респондент с нормальным NSWindow. Я просто не могу сделать это с помощью меню в строке состояния.
2 ответа
Я понял это. Apple использует подкласс NSWindow NSCarbonMenuWindow
для реализации меню. Итак, я получаю сообщение menuWillOpen: я немного жду, пока откроется меню, я получаю последнее окно (только что созданное - окно меню) и делаю ползунок первым ответчиком. Теперь все работает!
- (void)menuWillOpen: (NSMenu*)menu
{
if (menu == statusBarMenu) {
[NSThread detachNewThreadSelector: @selector(threadedMenuWillOpen) toTarget: self withObject: nil];
}
}
- (void)threadedMenuWillOpen
{
[NSThread sleepForTimeInterval: 0.1];
NSArray* windows = [NSApp windows];
NSWindow* menuWindow = [windows lastObject]; // The last window is the one I want because it has just been created
if ([[menuWindow className] isEqualToString: @"NSCarbonMenuWindow"]) {
[menuWindow makeFirstResponder: bSlider];
}
}
- (void)keyDown: (NSEvent*)theEvent
{
unsigned short keyCode = [theEvent keyCode];
if (keyCode == 126) { // up-arrow
[[NSNotificationCenter defaultCenter] postNotificationName:@"upArrow" object:nil];
}
else if (keyCode == 125) { // down-arrow
[[NSNotificationCenter defaultCenter] postNotificationName:@"DownArrow" object:nil];
} else
{
[super keyDown:theEvent];
}
}