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

Kie*_*ran 9 right-click nsmenu nsstatusitem swift osx-yosemite

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

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

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

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

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

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

rob*_*cer 5

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

另请注意,popUpStatusItemMenu:从OS X 10.10(Yosemite)开始,该软件已被"轻度弃用",并将在未来版本中正式弃用.目前,它有效,不会给你任何警告.希望在正式弃用之前,我们将有一个完全支持的方式来做这件事 - 如果您同意,我建议您提交错误报告.

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

typedef NS_ENUM(NSUInteger,JUNStatusItemActionType) {
    JUNStatusItemActionNone,
    JUNStatusItemActionPrimary,
    JUNStatusItemActionSecondary
};

@property (nonatomic, strong) NSStatusItem *statusItem;
@property (nonatomic, strong) NSMenu *statusItemMenu;
@property (nonatomic) JUNStatusItemActionType statusItemAction;
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)

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

- (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
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

所以基本上,handleStatusItemAction:鼠标按下并鼠标按下鼠标按钮.当按钮关闭时,它会跟踪它是应该执行主要操作还是辅助操作.如果它是次要操作,则会立即处理,因为菜单通常会在鼠标按下时出现.如果它是主要动作,那就是在鼠标上进行处理.