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 菜单行为(例如,仅在鼠标右键单击时显示)的主要内容,如果未能解决你的问题,请参考以下文章
OSX Yosemite 10.10 上 Xamarin 中的 PCL 库