按Option键,在应用程序主菜单中隐藏/显示菜单项

Vla*_*kov 9 cocoa nsmenu

我想在应用程序的主菜单中添加一个菜单项,这将很少使用.我希望默认情况下隐藏它并仅在用户按住Option键时显示它.我该怎么做呢?

看来我应该处理flagsChanged:,但这是NSResponder方法而NSMenu不是继承NSResponder?我在主窗口控制器中尝试了它,当我点击菜单之前按下Option键时它可以正常工作.以下用例不起作用:单击菜单项(没有项目),按选项键 - 我的项目应该出现,释放选项键 - 项目应该消失.

我也试着NSEvent的addLocalMonitorForEventsMatchingMask:handler:addGlobalMonitorForEventsMatchingMask:handler:用于NSFlagsChangedMask但是当同时打开主菜单无论本地或全局处理程序不会触发选项键按下.

我怎样才能做到这一点?

Mat*_*ens 11

构建菜单时包含可选项并将其标记为隐藏.然后将类实例设置为菜单的委托,并在菜单打开时添加运行循环观察器以控制可选项的隐藏状态.

@implementation AppController {
    CFRunLoopObserverRef _menuObserver;
}

- (void)updateMenu {
    BOOL hideOptionalMenuItems = ([NSEvent modifierFlags] & NSAlternateKeyMask) != NSAlternateKeyMask;
    [self.optionalMenuItem setHidden:hideOptionalMenuItems];
}

- (void)menuWillOpen:(NSMenu *)menu {
    [self updateMenu];

    if (_menuObserver == NULL) {
        _menuObserver = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
            [self updateMenu];
        });

        CFRunLoopAddObserver(CFRunLoopGetCurrent(), _menuObserver, kCFRunLoopCommonModes);
    }
}

- (void)menuDidClose:(NSMenu *)menu {
    if (_menuObserver != NULL) {
        CFRunLoopObserverInvalidate(_menuObserver);
        CFRelease(_menuObserver);
        _menuObserver = NULL;
    }
}
Run Code Online (Sandbox Code Playgroud)


Psy*_*cho 11

实现这一目标的最佳方法是使用两个菜单项,第一个菜单项使用高度为0的自定义视图,并且已禁用,然后在其下方是"备用"项.(您必须将此项目设置keyEquivalentModifierMaskNSAlternateKeyMask)使用此安排,当您按下选项键时,NSMenu将自动将零高度菜单项替换为备用项目,这将使菜单项神奇地出现.

无需定时器,更新或标记更改通知.

此功能在此处的文档中进行了描述:管理备用


小智 7

将以下内容添加到applicationDidFinishLaunching中.

// Dynamically update QCServer menu when option key is pressed
NSMenu *submenu = [[[NSApp mainMenu] itemWithTitle:@"QCServer"] submenu];    
NSTimer *t = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(updateMenu:) userInfo:submenu repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSEventTrackingRunLoopMode];
Run Code Online (Sandbox Code Playgroud)

然后加

- (void)updateMenu:(NSTimer *)t {

    static NSMenuItem *menuItem = nil;
    static BOOL isShowing = YES;

    // Get global modifier key flag, [[NSApp currentEvent] modifierFlags] doesn't update while menus are down
    CGEventRef event = CGEventCreate (NULL);
    CGEventFlags flags = CGEventGetFlags (event);
    BOOL optionKeyIsPressed = (flags & kCGEventFlagMaskAlternate) == kCGEventFlagMaskAlternate;
    CFRelease(event);

    NSMenu *menu = [t userInfo];

    if (!menuItem) {
        // View Batch Jobs...
         menuItem = [menu itemAtIndex:6];
        [menuItem retain];
    }

    if (!isShowing && optionKeyIsPressed) {
        [menu insertItem:menuItem atIndex:6];
        [menuItem setEnabled:YES];
        isShowing = YES;
    } else if (isShowing && !optionKeyIsPressed) {
        [menu removeItem:menuItem];
        isShowing = NO;
    }

    NSLog(@"optionKeyIsPressed %d", optionKeyIsPressed);
}
Run Code Online (Sandbox Code Playgroud)

计时器仅在跟踪控件时触发,因此不会影响性能.