弹出窗口处于状态栏时的NSPopover过渡

rad*_*dex 17 cocoa statusbar popover nsstatusbar osx-lion

我正在制作一个位于状态栏的应用程序.单击状态项时,将弹出NSPopover.

它看起来像这样:

在此输入图像描述

这就是问题所在:我希望它是"瞬态的",即如果我点击弹出窗口外的任何地方,它就会关闭.虽然当弹出窗口在窗口中时NSPopoverBehaviorTransient正常工作,但当它在状态栏中时它不起作用.

我怎样才能自己实现这种行为?

rad*_*dex 28

结果很简单:

- (IBAction)openPopover:(id)sender
{
    // (open popover)

    if(popoverTransiencyMonitor == nil)
    {
        popoverTransiencyMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask handler:^(NSEvent* event)
                                    {
                                        [self closePopover:sender];
                                    }];
    }
}

- (IBAction)closePopover:(id)sender
{
    if(popoverTransiencyMonitor)
    {
        [NSEvent removeMonitor:popoverTransiencyMonitor];

        popoverTransiencyMonitor = nil;
    }

    // (close popover)
}
Run Code Online (Sandbox Code Playgroud)

但是,不容易的是,有一个令人讨厌的问题,即弹出一个弹出的NSStatusItem(当调用Mission Control或空间切换到全屏窗口时,它没有按预期运行).我必须实现一个自定义窗口,它始终浮动在NSStatusItem之上,并处理切换到全屏窗口等.这似乎很容易,但显然状态项不是为那样的东西设计的;)

  • 对于与系统状态项的一致行为:`addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask | NSRightMouseDownMask` - 以便右键单击也关闭弹出窗口. (5认同)

wig*_*ing 8

我使用的方法类似于上面的答案,除了我将所有内容组合成一个方法而不是使用两个单独的IBAction.

首先,我声明以下属性

@property (strong, nonatomic) NSStatusItem *statusItem;
@property (strong, nonatomic) NSEvent *popoverTransiencyMonitor;
@property (weak, nonatomic) IBOutlet NSPopover *popover;
@property (weak, nonatomic) IBOutlet NSView *popoverView;
Run Code Online (Sandbox Code Playgroud)

然后在awakeFromNib中设置状态栏项

- (void)awakeFromNib {

    self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];

    self.statusItem.title = @"Title";
    self.statusItem.highlightMode = YES;
    self.statusItem.action = @selector(itemClicked:);
}
Run Code Online (Sandbox Code Playgroud)

然后是单击状态栏项时调用的方法

- (void)itemClicked:(id)sender {

    [[self popover] showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];

    if (self.popoverTransiencyMonitor == nil) {
        self.popoverTransiencyMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDownMask | NSRightMouseDownMask | NSKeyUpMask) handler:^(NSEvent* event) {
            [NSEvent removeMonitor:self.popoverTransiencyMonitor];
            self.popoverTransiencyMonitor = nil;
            [self.popover close];
        }];
    }
}
Run Code Online (Sandbox Code Playgroud)

当用户在视图外部单击时,弹出窗口会显示并关闭.

请注意,在Interface Builder中,您必须将弹出窗口的行为设置为Transient,以便在用户单击状态项时弹出窗口将关闭.