NSMenu 未调用 validateMenuItem 或 menuWillOpen

2024-05-27

我的 Mac 应用程序有一个 NSMenu,其委托功能validateMenuItem and menuWillOpen从来没有被调用过。到目前为止,网上的解决方案都没有帮助。

看来我做的一切都是对的:

  • 菜单项的选择器属于同一类。
  • 管理它的类继承自 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)
    }
}

menuWillOpen:属于NSMenuDelegate协议;要调用该菜单,需要一个委托:

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

validateMenuItem:属于NSMenuValidation非正式协议;以便将其称为相关菜单items必须有一个target。以下段落摘自Apple应用程序菜单和弹出列表编程主题 https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MenuList/Articles/EnablingMenuItems.html文档:

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

let myMenuItem = NSMenuItem()
myMenuItem.target = self
myMenuItem.action = #selector(doSomething)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NSMenu 未调用 validateMenuItem 或 menuWillOpen 的相关文章

随机推荐

  • 图例中标签的悬停样式

    如何设置图例中标签的悬停样式 如果可以设置的话cursor default在此示例中 将鼠标悬停在 东京 纽约 柏林 伦敦 标签上http www highcharts com demo http www highcharts com de
  • 如何运行 Windows 批处理文件但隐藏命令窗口?

    如何运行 Windows 批处理文件但隐藏命令窗口 我不希望 cmd exe 在执行文件时在屏幕上可见 这可能吗 如果你写一个非托管程序并使用创建进程 https learn microsoft com en us windows win3
  • RecyclerView 滚动不适用于 NestedScrollView

    我有一个布局 其中有一个 NestedScrollView 其中包含一个图像 多个按钮和一个 RecycleView 当我说recyclerView smoothScrollToPosition or recyclerView scroll
  • 如何在 Flask/SQLAlchemy 中 select_lated() ?

    有以下型号 class Question db Model id db Column db Integer primary key True title db Column db String 125 text db Column db T
  • 防止表单提交时出现默认 jQuery

    这有什么问题吗 HTML
  • 显示模板中存储为二进制 blob 的图像

    我有一个模型 其中图像存储为二进制 blob 我想在模板中显示该图像以及有关该对象的其他数据 由于图像不是一个单独的文件 我不知道如何显示它 我尝试过设置标题 或使用send file or render template 但我要么没有得到
  • 如何使用FeatureUnion转换PipeLine中的多个特征?

    我有一个 pandas 数据框 其中包含有关用户发送的消息的信息 对于我的模型 我感兴趣的是预测消息的缺失收件人 即给定消息的收件人 A B C 我想预测还有谁应该成为收件人的一部分 我正在使用 OneVsRestClassifier 和
  • 从多个文件加载 Flask 配置

    我需要从多个文件加载配置 我使用下面的代码来加载一个文件 我应该反复使用它吗 如何加载多个配置 app Flask name app config from object yourapplication default settings 您
  • 收到 404 时模型的 EmberJS 路由

    同样的文本也在 EmberJS 讨论区中开放 我有以下路线 App IndexCrmPersonEditRoute Ember Route extend model function params var person this store
  • 如何使用 CSS 使表格中的分隔线/边框消失?

    我有一个简单的 HTML 表格 我希望分隔线 边框 消失 所需的最终结果是一个除了实际文本之外不可见的表格 我尝试将 border 属性设置为 0 但没有帮助 我应该使用什么正确的 CSS 属性 table tr td th border
  • 对 .NET Windows 安装程序应用程序执行注册表搜索

    我有一个 NET winform 安装程序应用程序 在安装之前 我会进行注册表搜索以检查计算机上是否安装了 MS Access Runtime 搜索目标机器 搜索目标机器的属性 启动条件 启动条件的属性 但是我想避免对路径进行硬编码 例如
  • SWIG 类型映射 uint8_t* 从 C/C++ 到 java.nio.ByteBuffer

    我正在尝试将输入和输出缓冲区从 C 传递给 java 类 出于效率原因 我需要使用 ByteBuffer 这两个缓冲区都是在 C 部分中分配的 我需要将它们传递给一个 java 函数 该函数将使用输入缓冲区进行一些计算并将结果写入输出缓冲区
  • Fabric sudo 无密码解决方案

    这个问题是关于最佳实践的 我正在使用 Fabric 运行部署脚本 我的部署用户 deploy 需要 sudo 来重新启动服务 因此 我使用 Fabric 中的 sudo 函数在脚本中运行这些命令 这工作正常 但在脚本执行期间提示输入密码 我
  • MotionLayout:如何限制特定视图上的“OnSwipe”事件而不是整个屏幕上的“OnSwipe”事件

    我有一个带有以下 layoutDescription 场景文件 的运动布局
  • 如何在 xquery 中格式化小数?

    我正在尝试在 XQuery 中格式化小数 小数点是货币 所以格式应该是 例如 5573652 23应该5 573 652 23 and 352769应该352 769 or 352 769 00如果它更容易 更干净 现在我正在使用这个功能h
  • Angular2 - 自定义 CSS / JS 文件的文件夹是什么? [复制]

    这个问题在这里已经有答案了 我必须在我的 angular2 应用程序中包含一组 CSS 和 JS 文件 为了将它们包含在内 正确的文件夹是什么当我进行构建时 我应该把它们放进去吗SRC 资产或以下SRC 我的文件夹 定义后 我如何将它们包含
  • 如何在php中用一行调用两个方法?

    我在 Laravel 中看到在单行中调用多个方法 例如 DB get test gt toJson 我在该类中有一个很酷的类和视图方法 this gt call gt view welcome gt anotherMethod 我还想调用另
  • 如何在 TypeScript 中输入这个“as”JSX 属性?

    我正在描述一个 React 库 它通过名为的属性获取组件或 HTML 标签名称as 当给出as属性 它根据该组件 标签名称创建一个元素 并传递任何其他给定的属性 这里有些例子
  • 指纹已经被gitlab采集了

    我格式化了我的 Windows 7 笔记本电脑 并尝试让 git 设置再次工作 我安装了 git 和源代码树应用程序 我从 gitlab 删除了 SSH 密钥并使用重新生成了密钥ssh keygen 但是当我尝试在 gitlab 添加 SS
  • NSMenu 未调用 validateMenuItem 或 menuWillOpen

    我的 Mac 应用程序有一个 NSMenu 其委托功能validateMenuItem and menuWillOpen从来没有被调用过 到目前为止 网上的解决方案都没有帮助 看来我做的一切都是对的 菜单项的选择器属于同一类 管理它的类继承