我正在Swift中编写一个简单的状态栏应用程序,并尝试使用OS X 10.10中引入的新NSStatusItem API。
我所瞄准的界面是在statusItem上单击鼠标左键,可以打开和关闭核心功能,只需右键单击(或按住Control键单击)选项即可显示设置菜单。我不需要自定义视图或弹出窗口来实现此功能。
默认情况下,如果将NSMenu分配给NSStatusItem,它将同时显示左右两侧的菜单。我想将行为更改为仅在右键单击时显示菜单,或者作为解决方法,防止左键单击菜单弹出
以前,似乎要控制NSStatusItem上的鼠标事件,必须使用重写的鼠标事件设置自定义视图(请参阅this related question)。
在10.10中引入的新NSStatusItem API中,不推荐使用设置自定义视图的方法,并且看起来不鼓励这种行为。根据{{3}}中的@Taylor,应该通过statusItemObject.button()返回的NSStatusBarButton对象使用一些不赞成的行为,但是在编写时没有NSStatusBarButton的文档,并且返回的对象是只读的,不能用带有重写鼠标事件处理程序的自定义按钮替换。
是否有办法对鼠标事件中是否显示附加到NSStatusItem(或NSStatusBarButton)的NSMenu进行某种程度的控制?
答案 0 :(得分:5)
这是我提出的解决方案。它工作得相当好,虽然有一件事我不满意:在右键菜单中选择一个选项后,状态项会保持高亮显示。一旦你与其他东西互动,亮点就会消失。
另请注意,自OS X 10.10(优胜美地)起,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:
并在两个鼠标按钮上按下鼠标。当按钮关闭时,它会跟踪它是应该执行主要操作还是辅助操作。如果它是次要操作,则会立即处理,因为菜单通常会在鼠标按下时出现。如果这是一个主要动作,那就是在鼠标上进行处理。
答案 1 :(得分:0)
这在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并且应该有效)