NSPopover, если всплывающее окно находится в строке состояния
Я делаю приложение, которое живет в строке состояния. При щелчке по элементу состояния появляется NSPopover.
Это выглядит так:
Вот проблема: я хочу, чтобы он был "временным", то есть если я щелкну где-нибудь за пределами поповера, он закроется. И хотя NSPopoverBehaviorTransient работает нормально, когда popover находится в окне, он не работает, когда он находится в строке состояния.
Как я могу реализовать такое поведение самостоятельно?
2 ответа
Это оказалось легко:
- (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 и имеет дело с переключением в полноэкранное окно и т. Д. Это казалось простым, но ясно, что элементы состояния не были предназначены для чего-то подобного;)
Подход, который я использую, аналогичен приведенному выше ответу, за исключением того, что у меня все объединено в один метод вместо двух отдельных 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, чтобы всплывающее окно закрывалось, когда пользователь щелкает элемент состояния.