Home > Blockchain >  How to programatically close NSPopover being used in Mac Menu bar app
How to programatically close NSPopover being used in Mac Menu bar app

Time:02-08

Apologies as this is a beginner question. I am using https://github.com/davidcaddy/MenuBarPopoverExample to create a simple menu bar app.

I have added a button in the viewController and connected it.

What would the command be to simply close the NSPopover (see commented section below)?

View Controller Code:

import Cocoa

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

    static func newInstance() -> ViewController {
        let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil)
        let identifier = NSStoryboard.SceneIdentifier("ViewController")
      
        guard let viewcontroller = storyboard.instantiateController(withIdentifier: identifier) as? ViewController else {
            fatalError("Unable to instantiate ViewController in Main.storyboard!")
        }
        return viewcontroller
    }
    
    
    @IBAction func closePopover(_ sender: Any) {
        print("close this popover")
        
        // what code would I put here??
       // closePopover(self)?

    }
}

AppDeligate code (untouched from example):

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength)
    let popover = NSPopover()
    var eventMonitor: EventMonitor?
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        if let button = self.statusItem.button {
            button.image = NSImage(named: NSImage.Name("ExampleMenuBarIcon"))
            button.action = #selector(AppDelegate.togglePopover(_:))
            
            // Uncomment this to capture right mouse clicks, in addition to left clicks
            //
            // button.sendAction(on: [.leftMouseUp, .rightMouseUp])
        }
        
        self.popover.contentViewController = ViewController.newInstance()
        self.popover.animates = false
        
        self.eventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown]) { [weak self] event in
            if let strongSelf = self, strongSelf.popover.isShown {
                strongSelf.closePopover(sender: event)
            }
        }
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        // Insert code here to tear down your application
    }

    @objc func togglePopover(_ sender: NSStatusItem) {
        // if sendAction(on: [.leftMouseUp, .rightMouseUp]) is uncommented in applicationDidFinishLaunching
        // This can be used to check the type of the incoming mouse event
        //
        // let event = NSApp.currentEvent!
        // if event.type == NSEvent.EventType.rightMouseUp {
        //     print("Right Click")
        // }
        
        if self.popover.isShown {
            closePopover(sender: sender)
        }
        else {
            showPopover(sender: sender)
        }
    }

    func showPopover(sender: Any?) {
        if let button = self.statusItem.button {
            self.popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
            self.eventMonitor?.start()
        }
    }

    func closePopover(sender: Any?) {
        self.popover.performClose(sender)
        self.eventMonitor?.stop()
    }
}

I have tried every command I can find online and none of them allow me to close the popover programatically from within the ViewController. I would appreciate any assistance you can provide.

CodePudding user response:

Just get the AppDelegate instance

@IBAction func closePopover(_ sender: Any) {
    let appDelegate = NSApp.delegate as! AppDelegate
    appDelegate.closePopover(self)
}

Note: As the sender parameter is actually not being used you can omit it in the show and close functions

func showPopover()
  •  Tags:  
  • Related