首页 文章

Swift:10.10中的NSStatusItem菜单行为(例如,只在鼠标右键单击时显示)

提问于
浏览
9

我正在Swift中编写一个简单的状态栏应用程序,并尝试使用OS X 10.10中引入的新NSStatusItem API .

我瞄准的界面是在statusItem上单击鼠标左键以打开和关闭核心功能,用鼠标右键单击(或按住Control键单击)选项以显示设置菜单 . 我不需要自定义视图或弹出窗口来实现此功能 .

默认情况下,如果NSMenu被分配给NSStatusItem,它将在左右键单击上显示菜单 . 我想将行为更改为仅在右键单击时显示菜单,或者作为解决方法,防止左键单击时弹出菜单

以前,似乎要在NSStatusItem上控制鼠标事件,必须使用重写的鼠标事件设置自定义视图(请参阅this related question) .

在10.10中引入的新NSStatusItem API中,不推荐使用设置自定义视图的方法,并且看起来不鼓励这种行为 . 根据@Taylor在this answer中的一些不赞成的行为应该通过statusItemObject.button()返回的NSStatusBarButton对象使用,但是在编写时没有NSStatusBarButton的文档,并且返回的对象是只读的,不能替换为带有重写鼠标事件处理程序的自定义按钮 .

有没有办法对鼠标事件显示附加到NSStatusItem(或NSStatusBarButton)的NSMenu进行某种程度的控制?

2 回答

  • 0

    这是我提出的解决方案 . 虽然有一件事我不满意,但它的效果相当不错:在右键菜单中选择一个选项后,状态项会保持高亮显示 . 一旦你与其他东西互动,亮点就消失了 .

    另请注意,自OS X 10.10(优胜美地)起 popUpStatusItemMenu: 是"softly deprecated",并将在以后的版本中正式弃用 . 就目前而言,它有效并赢得't give you any warnings. Hopefully we' ll有一个完全支持的方式来做到这一点's formally deprecated—I' d建议filing a bug report如果你同意 .

    首先,您需要一些属性和枚举:

    typedef NS_ENUM(NSUInteger,JUNStatusItemActionType) {
        JUNStatusItemActionNone,
        JUNStatusItemActionPrimary,
        JUNStatusItemActionSecondary
    };
    
    @property (nonatomic, strong) NSStatusItem *statusItem;
    @property (nonatomic, strong) NSMenu *statusItemMenu;
    @property (nonatomic) JUNStatusItemActionType statusItemAction;
    

    然后在某些时候你会想要设置状态项:

    NSStatusItem *item = [[NSStatusBar systemStatusBar] statusItemWithLength:29.0];
    NSStatusBarButton *button = item.button;
    button.image = [NSImage imageNamed:@"Menu-Icon"];
    button.target = self;
    button.action = @selector(handleStatusItemAction:);
    [button sendActionOn:(NSLeftMouseDownMask|NSRightMouseDownMask|NSLeftMouseUpMask|NSRightMouseUpMask)];
    self.statusItem = item;
    

    然后,您只需处理状态项按钮发送的操作:

    - (void)handleStatusItemAction:(id)sender {
    
        const NSUInteger buttonMask = [NSEvent pressedMouseButtons];
        BOOL primaryDown = ((buttonMask & (1 << 0)) != 0);
        BOOL secondaryDown = ((buttonMask & (1 << 1)) != 0);
        // Treat a control-click as a secondary click
        if (primaryDown && ([NSEvent modifierFlags] & NSControlKeyMask)) {
            primaryDown = NO;
            secondaryDown = YES;
        }
    
        if (primaryDown) {
            self.statusItemAction = JUNStatusItemActionPrimary;
        } else if (secondaryDown) {
            self.statusItemAction = JUNStatusItemActionSecondary;
            if (self.statusItemMenu == nil) {
                NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
                [menu addItemWithTitle:NSLocalizedString(@"Quit",nil) action:@selector(terminate:) keyEquivalent:@""];
                self.statusItemMenu = menu;
            }
            [self.statusItem popUpStatusItemMenu:self.statusItemMenu];
        } else {
            self.statusItemAction = JUNStatusItemActionNone;
            if (self.statusItemAction == JUNStatusItemActionPrimary) {
                // TODO: add whatever you like for the primary action here
            }
        }
    
    }
    

    基本上, handleStatusItemAction: 在鼠标按下时被调用,鼠标按下鼠标按钮 . 当按钮关闭时,它会跟踪它是应该执行主要操作还是辅助操作 . 如果立即处理's a secondary action, that',因为菜单通常会在鼠标按下时出现 . 如果它在鼠标上处理's a primary action, that' .

  • 5

    这在10.10中已弃用,但将继续有效:

    [self.statusItem setTarget:self]; // Otherwise this goes to the first responder
    [self.statusItem setAction:@selector(statusItemClicked:)];
    [self.statusItem sendActionOn:(NSRightMouseUpMask)];
    

    您可以通过bitmask来设置setActionOn中的其他事件 . 因此,例如,如果您想要左右键单击:

    [self.statusItem sendActionOn:(NSLeftMouseUpMask | NSRightMouseUpMask)];
    

    (请原谅objC,你应该能够把它翻译成swift,它应该工作)

相关问题