NSPopover, если всплывающее окно находится в строке состояния - PullRequest
17 голосов
/ 29 января 2012

Я делаю приложение, которое живет в строке состояния.При щелчке по элементу состояния появляется NSPopover.

Это выглядит следующим образом:

enter image description here

Вот проблема: я хочу, чтобы он был «временным»если я щелкну где-нибудь за пределами поповера, он закроется.И хотя NSPopoverBehaviorTransient отлично работает, когда popover находится в окне, он не работает, когда он находится в строке состояния.

Как самому реализовать такое поведение?

Ответы [ 2 ]

28 голосов
/ 13 февраля 2012

Оказалось, что это просто:

- (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 (оно не работает должным образом,Был запущен контроль полетов или пространство переключилось в полноэкранное окно).Мне пришлось реализовать собственное окно, которое всегда всплывает над NSStatusItem и имеет дело с переключением в полноэкранное окно и т. Д. Это казалось простым, но ясно, что элементы состояния не были предназначены для чего-то подобного;)

8 голосов
/ 12 апреля 2014

Подход, который я использую, аналогичен приведенному выше ответу, за исключением того, что я объединил все в один метод вместо двух отдельных IBA-операций.

Сначала я объявляю следующие свойства

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

, который заставляет всплывающее окно появляться и закрываться, когда пользователь щелкает за пределами представления.

Обратите внимание, что в Интерфейсном Разработчике вы должны установить поведение всплывающего окна на Transient, чтобы всплывающее окно закрывалось, когда пользователь щелкает элемент состояния.

...