简体   繁体   中英

menu items disabled in macOS menubar App

I'm trying to build a menubar app on macOS.

I can't seem to figure out why some menu items are disabled... Screenshot:

该应用的屏幕截图

As you can see, the Quit menu item is enabled, and quits the app when clicked. The Preferences item is disabled however.

My code

AppDelegate.swift:

let menuBarItem = NSStatusBar.system().statusItem(withLength: NSSquareStatusItemLength)

func applicationDidFinishLaunching(_ aNotification: Notification) {
    menuBarItem.button?.image = NSImage(named: "MenuBarIcon")
    menuBarItem.menu = MenuBarMenu()
}

MenuBarMenu.swift:

class MenuBarMenu: NSMenu {
    init() {
        super.init(title: "Menu")
        self.addItem(withTitle: "Preferences...", action: #selector(MenuBarActions.openPreferencesWindow(_:)), keyEquivalent: "")
        self.addItem(NSMenuItem.separator())
        self.addItem(withTitle: "Quit", action: #selector(MenuBarActions.terminate(_:)), keyEquivalent: "")
    }

    required init(coder decoder: NSCoder) {
        fatalError("init(coder:) has not been impemented")
    }
}

class MenuBarActions {
    @objc static func terminate(_ sender: NSMenuItem) {
        NSApp.terminate(sender)
    }

    @objc static func openPreferencesWindow(_ sender: NSMenuItem) {
        print("preferences")
    }
}

I am using the exact same way to create both MenuBarItems and the same structure for the selectors, so I am a little confused by this inconsistency. What is the reason this happens and how can I solve this problem?

Your Quit menu item is working "accidentally". It is not using the terminate(_:) method you implemented. Put a print() statement there and you'll see it's not being invoked.

A menu item either has a specific target object assigned or it uses the responder chain to search for an appropriate target. You are not assigning a target for your menu items, so they are using the responder chain. Your MenuBarActions class is not part of the responder chain. (Classes generally can't be. Certain objects can be.) So, the menu items will never target your class.

The Quit menu works because the application object is on the responder chain and it has a terminate(_:) method. In fact, that's what your terminate(_:) method would invoke if it were ever being called. But the menu item is actually invoking it directly.

You should create an actual controller object (not just class) that implements the action methods and set the menu items' target property to it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM