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

Posted

技术标签:

【中文标题】Swift:10.10 中的 NSStatusItem 菜单行为(例如,仅在鼠标右键单击时显示)【英文标题】:Swift: NSStatusItem menu behaviour in 10.10 (e.g. show only on right mouse click) 【发布时间】:2015-01-11 12:25:23 【问题描述】:

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

我的目标是在 statusItem 上单击鼠标左键以打开和关闭核心功能,然后单击鼠标右键(或 control-click)选项以显示设置菜单。我不需要此功能的自定义视图或弹出框。

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

以前,似乎要控制 NSStatusItem 上的鼠标事件,必须设置一个自定义视图并覆盖鼠标事件(请参阅this related question)。

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

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

【问题讨论】:

【参考方案1】:

这是我想出的解决方案。它工作得相当好,但有一点我不满意:在右键单击菜单中选择一个选项后,状态项保持突出显示。一旦您与其他事物互动,突出显示就会消失。

另请注意,从 OS X 10.10 (Yosemite) 开始,popUpStatusItemMenu: 已“轻度弃用”,并将在未来的版本中正式弃用。目前,它可以工作并且不会给你任何警告。希望在正式弃用之前,我们将有一种完全支持的方式来执行此操作 - 如果您同意,我建议您使用 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: 在鼠标按下和鼠标按下时都会调用两个鼠标按钮。当按钮按下时,它会跟踪它是否应该执行主要操作或次要操作。如果它是辅助操作,则会立即处理,因为菜单通常出现在鼠标按下时。如果是主要操作,则在鼠标上移时进行处理。

【讨论】:

一些注意事项(以下 sn-ps 在 Swift 中): a) 您可以通过为 StatusItem 对象设置item.highlightMode = false 来解决右键单击后剩余的突出显示。 b) 主要操作的案例应该首先出现在最后的 else 块中(在self.statusItemAction = JUNStatusItemActionNone; 之前),以使所需的行为起作用。否则,您将设置 self.statusItemAction 的值,然后立即检查它是否有所不同。【参考方案2】:

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

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

您可以通过位掩码在 setActionOn 中设置其他事件。因此,例如,如果您想要左右单击:

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

(对不起,objC,你应该可以把它翻译成swift,它应该可以工作)

【讨论】:

以上是关于Swift:10.10 中的 NSStatusItem 菜单行为(例如,仅在鼠标右键单击时显示)的主要内容,如果未能解决你的问题,请参考以下文章

Swift 特殊关键字

OSX Yosemite 10.10 上 Xamarin 中的 PCL 库

JVM 从哪里获得 ubuntu 10.10 中的语言环境设置?

OS X 10.10中的自定义NSControl类

Swift写简易计算器

Swift Package Manager 重写 macOS 部署目标