2016-07-19 16 views
1

我的Mac应用程序有一个NSMenu,其代理函数validateMenuItemmenuWillOpen永远不会被调用。到目前为止,网上的解决方案都没有帮助。validateMenuItem或menuWillOpen不需要NSMenu

好像我做的一切权利:

  • 菜单项的选择是在同一个班级。
  • 类管理从NSMenuDelegate

继承我想描述我的问题的最好办法是张贴相关的代码。任何帮助,将不胜感激。

import Cocoa 

class UIManager: NSObject, NSMenuDelegate {  
    var statusBarItem = NSStatusBar.system().statusItem(withLength: -2) 
    var statusBarMenu = NSMenu() 
    var titleMenuItem = NSMenuItem() 
    var descriptionMenuItem = NSMenuItem() 

    // ... 

    override init() {    
     super.init() 

     createStatusBarMenu() 
    } 

    // ... 

    func createStatusBarMenu() { 
     // Status bar icon 
     guard let icon = NSImage(named: "iconFrame44") 
      else { NSLog("Error setting status bar icon image."); return } 
     icon.isTemplate = true 
     statusBarItem.image = icon 

     // Create Submenu items 
     let viewOnRedditMenuItem = NSMenuItem(title: "View on Reddit...", action: #selector(viewOnRedditAction), keyEquivalent: "") 
     let saveThisImageMenuItem = NSMenuItem(title: "Save This Image...", action: #selector(saveThisImageAction), keyEquivalent: "") 

     // Add to title submenu 
     let titleSubmenu = NSMenu(title: "") 
     titleSubmenu.addItem(descriptionMenuItem) 
     titleSubmenu.addItem(NSMenuItem.separator()) 
     titleSubmenu.addItem(viewOnRedditMenuItem) 
     titleSubmenu.addItem(saveThisImageMenuItem) 

     // Create main menu items 
     titleMenuItem = NSMenuItem(title: "No Wallpaperer Image", action: nil, keyEquivalent: "") 
     titleMenuItem.submenu = titleSubmenu 
     getNewWallpaperMenuItem = NSMenuItem(title: "Update Now", action: #selector(getNewWallpaperAction), keyEquivalent: "") 
     let preferencesMenuItem = NSMenuItem(title: "Preferences...", action: #selector(preferencesAction), keyEquivalent: "") 
     let quitMenuItem = NSMenuItem(title: "Quit Wallpaperer", action: #selector(quitAction), keyEquivalent: "") 

     // Add to main menu 
     let statusBarMenu = NSMenu(title: "") 
     statusBarMenu.addItem(titleMenuItem) 
     statusBarMenu.addItem(NSMenuItem.separator()) 
     statusBarMenu.addItem(getNewWallpaperMenuItem) 
     statusBarMenu.addItem(NSMenuItem.separator()) 
     statusBarMenu.addItem(preferencesMenuItem) 
     statusBarMenu.addItem(quitMenuItem) 

     statusBarItem.menu = statusBarMenu 
    } 

    // ... 

    // Called whenever the menu is about to show. we use it to change the menu based on the current UI mode (offline/updating/etc) 
    override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { 
     NSLog("Validating menu item") 
     if (menuItem == getNewWallpaperMenuItem) { 
      if wallpaperUpdater!.state == .Busy { 
       DispatchQueue.main.async { 
        self.getNewWallpaperMenuItem.title = "Updating Wallpaper..." 
       } 
       return false 
      } else if wallpaperUpdater!.state == .Offline { 
       DispatchQueue.main.async { 
        self.getNewWallpaperMenuItem.title = "No Internet Connection" 
       } 
       return false 
      } else { 
       DispatchQueue.main.async { 
        self.preferencesViewController.updateNowButton.title = "Update Now" 
       } 
       return true 
      } 
     } 

     return true 
    } 

    // Whenever the menu is opened, we update the submitted time 
    func menuWillOpen(_ menu: NSMenu) { 
     NSLog("Menu will open") 
     if !noWallpapererImageMode { 
      DispatchQueue.main.async { 
       self.descriptionMenuItem.title = "Submitted \(self.dateSimplifier(self.updateManager!.thisPost.attributes.created_utc as Date)) by \(self.updateManager!.thisPost.attributes.author) to /r/\(self.updateManager!.thisPost.attributes.subreddit)" 
      } 
     } 
    } 

    // ... 

    // MARK: User-initiated actions 

    func viewOnRedditAction() { 
     guard let url = URL(string: "http://www.reddit.com\(updateManager!.thisPost.permalink)") 
      else { NSLog("Could not convert post permalink to URL."); return } 
     NSWorkspace.shared().open(url) 
    } 

    // Present a save panel to let the user save the current wallpaper 
    func saveThisImageAction() { 
     DispatchQueue.main.async { 
      let savePanel = NSSavePanel() 
      savePanel.makeKeyAndOrderFront(self) 

      savePanel.nameFieldStringValue = self.updateManager!.thisPost.id + ".png" 
      let result = savePanel.runModal() 

      if result == NSFileHandlingPanelOKButton { 
       let exportedFileURL = savePanel.url! 
       guard let lastImagePath = UserDefaults.standard.string(forKey: "lastImagePath") 
        else { NSLog("Error getting last post ID from persistent storage."); return } 
       let imageData = try! Data(contentsOf: URL(fileURLWithPath: lastImagePath)) 
       if (try? imageData.write(to: exportedFileURL, options: [.atomic])) == nil { 
        NSLog("Error saving image to user-specified folder.") 
       } 
      } 
     } 
    } 

    func getNewWallpaperAction() { 
     updateManager!.refreshAndReschedule(userInitiated: true) 
    } 

    func preferencesAction() { 
     preferencesWindow.makeKeyAndOrderFront(nil) 
     NSApp.activateIgnoringOtherApps(true) 
    } 

    func quitAction() { 
     NSApplication.shared().terminate(self) 
    } 
} 
+1

您不会出现在你的代码设置菜单的委托。 –

+0

谢谢,解决了menuWillOpen问题。尽管如此,这并不能解决我与validateMenuItem的问题。 – yesthisisjoe

回答

4

menuWillOpen:属于NSMenuDelegate协议;它被称为所讨论的菜单需要委托:

let statusBarMenu = NSMenu(title: "") 
statusBarMenu.delegate = self 

validateMenuItem:属于NSMenuValidation非正式协议;因为它被称为相关菜单项目必须有一个target。下面的通道从苹果公司的Application Menu and Pop-up List Programming Topics资料为准:

当您使用自动菜单启用,NSMenu更新每当用户事件发生时,每个菜单项的状态。要更新菜单项的状态,NSMenu首先确定项目的目标,然后确定目标是否实现了validateMenuItem:或validateUserInterfaceItem :(按该顺序)。

let myMenuItem = NSMenuItem() 
myMenuItem.target = self 
myMenuItem.action = #selector(doSomething) 
+0

谢谢。在我的例子中,我添加了'statusBarMenu.delegate = self'这一行,并且在每个有动作的菜单项初始化后添加了'myMenuItem.target = self'。 – yesthisisjoe

+0

如果menuitem没有动作,validatemenuitem不会被调用吗? – tofutim