使用 NSMenu 上的箭头控制 NSStatusItem-Objective-C/Cocoa 的 NSSlider

发布于 2024-12-10 17:46:36 字数 1033 浏览 0 评论 0原文

我想创建一个状态项,其中有一个垂直滑块,很像苹果提供的声音控制。我的问题是:如何让它对向上/向下箭头键做出反应,就像声音菜单中的滑块一样?

我尝试创建一个 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 的第一响应者时它可以工作。我只是无法使用状态栏项目中的菜单来做到这一点。

I would like to create a status item with a vertical slider in it, much like the sound control provided by Apple. My question is: how do I make it react to the up/down arrow keys, just like the slider in the sound menu?

I have tried to create a NSSlider subclass that would increase/decrease its value when the keys are pressed (see below), but I need to make it the first responder. To make it the first responder I made the main class the delegate of this menu and added this method:

- (void)menuWillOpen: (NSMenu*)menu
{
    if (menu == statusBarMenu) {        
        [THE_WINDOW_THAT_CONTAINS_THE_SLIDER makeFirstResponder: slider];
}

Which window should I call? Should I do this any other way? How would you do this?

The slider subclass:

#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

I have tested it and it works when it is the first responder with a normal NSWindow. I just can't do it with a menu in a status bar item.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

拔了角的鹿 2024-12-17 17:46:36

我已经想通了。 Apple 使用名为 NSCarbonMenuWindow 的 NSWindow 子类来实现菜单。所以我收到了 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];
    }    
}

I have figured it out. Apple uses a NSWindow subclass called NSCarbonMenuWindow for implementing menus. So I get the menuWillOpen: message, I wait a bit for the menu to open, I get the last window (the one created just now - menu window) and I make the slider the firstResponder. It all works now!

- (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];
    }    
}
腹黑女流氓 2024-12-17 17:46:36
- (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];
    }
}
- (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];
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文