NSPopover - Hide when focus lost? (clicked outside of popover)
Asked Answered
F

4

19

I'm using the doubleClickAction of a NSTableView to display a NSPopover. Something like this:

NSInteger selectedRow = [dataTableView clickedRow];
NSInteger selectedColumn = [dataTableView clickedColumn];


// If something was not selected, then we cannot display anything.
if(selectedRow < 0 || selectedColumn < 0)
{
    NSLog(@"Invalid selected (%ld,%ld)", selectedRow, selectedColumn);
    return;
} // End of something was not selected

// Setup our view controller, make sure if there was already a popover displayed, that we kill that one off first. Finally create and display our new popover.
DataInspectorViewController * controller =
[[DataInspectorViewController alloc] initWithNibName: @"DataInspectorViewController"
                                              bundle: nil];

if(nil != dataPreviewPopover)
{
    [dataPreviewPopover close];
} // End of popover was already visible

dataPreviewPopover = [[NSPopover alloc] init];
[dataPreviewPopover setContentSize:NSMakeSize(400.0f, 400.0f)];
[dataPreviewPopover setContentViewController:controller];
[dataPreviewPopover setAnimates:YES];
[dataPreviewPopover showRelativeToRect: [dataTableView frameOfCellAtColumn: selectedColumn row: selectedRow]
                     ofView: dataTableView
              preferredEdge: NSMinYEdge];

Which works just fine. My popovers get created and removed on the cells that I double click on . The problem is, I want to the popover to go away if I click anywhere outside of it (like a single click on another cell). I have been looking around, but for the life of me cannot figure out how to do it.

This is something I would assume is built into a popover, (I'm fairly certain it was in the iOS UIPopoverController class) so I'm just wondering if im missing something simple.

Flavopurpurin answered 16/2, 2013 at 12:6 Comment(0)
H
69

You need to change the property behavior of your popover (in code or on interface builder) to:

popover.behavior = NSPopover.Behavior.transient;

NSPopover.Behavior.transient
The system will close the popover when the user interacts with a user interface element outside the popover.

Read more about this in Apple's documentation.

Hanseatic answered 17/2, 2013 at 14:45 Comment(2)
Is it possible to hide the popover when the user interacts with a user interface outside the application?Godthaab
In Objective-C: self.myPopover.behavior = NSPopoverBehaviorTransient;Cicatrix
J
14

the .transient flag doesn't work for me.

However I can make things work by the following:

1) Whenever I show my popover I make sure I activate the app (my app is a menu-bar app, so this doesn't happen automatically)

NSApp.activate(ignoringOtherApps: true)

2) When I click outside the app, then my app will be deactivated. I can detect this in the AppDelegate

func applicationWillResignActive(_ notification: Notification) {
    print("resign active")
}

and act accordingly

Jiffy answered 1/2, 2019 at 16:50 Comment(2)
This was of great help in Xamarin for MacOS using public override void WillResignActive(NSNotification notification)Intransigent
Although it's not working when clicking on another menu-bar app (my app is also a menu-bar app). But works well outside. Any ideas?Stokes
C
3

After calling show(relativeTo:of:preferredEdge:) method,

Add below line

popover.contentViewController?.view.window?.makeKey()

And make sure you set

popover.behavior = .transient

Sorry, I've added solution in Swift.

Chiller answered 11/8, 2022 at 14:44 Comment(0)
S
0

While transient worked for most cases, it was an issue when the user interacted with elements outside of the application, as the popover would hide but not close.

What finally ended working for me was:

popover.behavior = .semitransient

Now the popover closes when changing app, or interacting with any other element outside of the app. But will not close when interacting with a NSMenu, and maybe won't close either with other interactions.

Quoting from the documentation for NSPopover.Behavior.semitransient:

The exact interactions that cause semi-transient popovers to close are not specified.

Similar to the documentation for NSPopover.Behavior.transient:

The exact interactions that will cause transient popovers to close are not specified.

Shifra answered 12/6, 2021 at 11:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.