NSPopover在状态栏中时的瞬态特性

18
我正在制作一个生活在状态栏中的应用程序。当状态项目被点击时,NSPopover弹出。

它看起来像这样:

enter image description here

问题是:我希望它是“瞬态”的,也就是说,如果我在气泡之外的任何地方点击,它将关闭。而且当气泡位于窗口中时,NSPopoverBehaviorTransient工作正常,但当它在状态栏中时则不行。

我该如何自己实现这样的行为?

2个回答

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

然而,并不容易的是,在NSStatusItem弹出一个popover时存在一些讨厌的问题(当进入Mission Control或切换到全屏窗口时,它并没有像期望的那样表现)。我不得不实现一个自定义窗口,它始终浮在NSStatusItem上方,并处理切换到全屏窗口等问题。看起来很简单,但显然状态栏项目并没有为这样的事情设计 ;)


5
为了与系统状态项目的行为一致:addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask - 以便右键单击也可以关闭弹出窗口。 - inket

9
我的方法与上面的答案类似,不同之处在于我将所有内容都合并到一个方法中,而不是使用两个单独的IBActions。
首先,我声明以下属性。
@property (strong, nonatomic) NSStatusItem *statusItem;
@property (strong, nonatomic) NSEvent *popoverTransiencyMonitor;
@property (weak, nonatomic) IBOutlet NSPopover *popover;
@property (weak, nonatomic) IBOutlet NSView *popoverView;

然后在awakeFromNib中设置状态栏项目

- (void)awakeFromNib {

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

    self.statusItem.title = @"Title";
    self.statusItem.highlightMode = YES;
    self.statusItem.action = @selector(itemClicked:);
}

接下来是当状态栏项目被点击时调用的方法

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

此代码可以让弹出窗口出现,并在用户点击视图外部时关闭。

请注意,在接口构建器中,您必须将弹出窗口的行为设置为瞬态,以便当用户单击状态栏项目时,弹出窗口会关闭。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接