2016-07-19 5 views
1

Meine Mac-App hat ein NSMenu, dessen Delegiertenfunktionen validateMenuItem und menuWillOpen niemals aufgerufen werden. Bisher hat keine der Online-Lösungen geholfen.validateMenuItem oder menuWillOpen nicht für NSMenu aufgerufen

Es scheint, als ob ich alles richtig gemacht habe:

  • Die Selektoren des Menüpunktes in der gleichen Klasse sind.
  • Die Klasse erbt von NSMenuDelegate

Ich nehme an, den besten Weg, die Verwaltung, mein Problem zu beschreiben, ist der entsprechenden Code zu schreiben. Jede Hilfe wäre willkommen.

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

Sie erscheinen nicht im Menü des Delegierten überall in Ihrem Code einzustellen. –

+0

Danke, das hat das menuWillOpen Problem behoben. Das behebt mein Problem mit validateMenuItem jedoch nicht. – yesthisisjoe

Antwort

4

menuWillOpen: gehört zur NSMenuDelegate Protokoll; denn es ist das Menü in Frage braucht einen Delegaten aufgerufen werden:

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

validateMenuItem: gehört zum NSMenuValidation informellen Protokoll; damit es das relevante Menü genannt wird, müssen ein target haben. Die folgende Passage genommen wird Application Menu and Pop-up List Programming Topics Dokumentation von Apple:

Wenn Sie die automatische Menü aktivieren, aktualisiert NSMenu den Status jedes Menüpunkt, wenn ein Benutzer-Ereignis eintritt. Um den Status eines Menüelements zu aktualisieren, ermittelt NSMenu zunächst das Ziel des Elements und bestimmt dann, ob das Ziel validateMenuItem: oder validateUserInterfaceItem implementiert: (in dieser Reihenfolge).

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

Danke. In meinem Fall habe ich die Zeile 'statusBarMenu.delegate = self' hinzugefügt und' myMenuItem.target = self' nach der Initialisierung jedes Menüpunktes hinzugefügt, der eine Aktion hatte. – yesthisisjoe

+0

wenn der menüpunkt keine aktion hat, wird validitemenuitem nicht aufgerufen? – tofutim

Verwandte Themen