【问题标题】:validateMenuItem: not calledvalidateMenuItem:未调用
【发布时间】:2013-03-03 10:24:24
【问题描述】:

我正面临一个奇怪的情况。我有一个NSMenu,里面有一个子菜单。子菜单的内容以编程方式填充。在我的 validateMenuItem: 方法中,我可以看到所有正在检查的项目(父项目)以及子项目(一旦我点击子菜单),除了那些在我的自动填充子菜单中的项目。

这是为什么呢?难道我做错了什么?关于如何解决这个问题的任何想法?

【问题讨论】:

  • 这些菜单项在其他情况下正常运行(即当您选择它们​​时,它们会触发它们的操作方法)?
  • @trojanfoe 刚刚找到答案(说实话很简单......) - 我现在就发布它。
  • @trojanfoe 所有菜单项的操作都在控制器中实现,而某个特定子菜单的子项的操作则没有。因此,不会调用validateMenuItem: 方法。 (令人沮丧......鉴于我在将它发布到 SO 之前 2 小时一直在努力解决它(然后在 10 分钟后自己回答......哈哈))
  • 只是谈论一个问题通常足以让您自己解决。
  • @trojanfoe 是的。奇怪但真实..

标签: objective-c macos cocoa nsmenu


【解决方案1】:

解决方案如下:

Cocoa 在 NSMenuItem 的动作选择器所在的 Class 中查找 validateMenuItem: 方法。

因此,如果您的NSMenuItem 的操作选择器(例如@selector(someSelector:))在SomeClass 中实现,那么请确保您在SomeClass 中也有一个validateMenuItem: 方法,如果您想验证相应的菜单项。

【讨论】:

  • 你的行动不是针对First Responder吗?
  • @trojanfoe 不,我不是。所有动作都链接到特定的类。我应该针对第一响应者吗?
  • 我想这取决于应用程序,但在我的基于文档的应用程序中,我认为所有菜单都针对 First Responder
  • 嗯,First Responder 是我很长时间以来一直想使用的东西之一,但是给定的(可能是我的控制狂的一部分......编码天性......哈哈) 我想 100% 知道什么去哪里,做什么 - 到目前为止我还没有尝试过什么(也许这不是最好的决定)。顺便说一句,我目前正在从事的(相当大的)项目确实也是一个基于文档的应用程序(但不是在严格的 Cocoa(参见:NSDocument)意义上......),所以您的意见可能会有所帮助。谢了哥们! :-)
  • 我敦促您尝试第一响应者 :) 它经常有帮助
【解决方案2】:

@Dr.Kameleon 有正确的答案。

如果可以的话,我会添加一个小点来更新它?我的代码最近在这方面发生了故障,并且在之前工作时停止调用 validateMenuItem:。我没有注意到,因为唯一的症状是一个菜单项在它应该被禁用时不再被禁用。

问题是 Swift 4。该方法必须使用 @objc 进行归因。在早期版本的 Swift 中,从 NSObject、NSViewController 等继承就足够了,但随着 Swift 4 和 5 的新版本发生变化。

附言将方法放在扩展中似乎很好。

【讨论】:

    【解决方案3】:

    以上答案并没有帮助我解决我的问题。我创建了一个单独的项目来了解何时调用 validateMenuItem(:) 方法。

    validateMenuItem(:) 方法仅在以下情况下被调用:

    1. 在实现NSPopUpButton的类中符合NSMenuItemValidation
    2. 所有 NSMenuItem 都必须将操作和目标设置为实现NSMenuItemValidation 协议的对象。
    3. 实现validateMenuItem(:) 方法。
    4. 为不执行任何操作的 NSMenuItem 实现 dummyAction(:) 方法。
    1. 必须设置 NSPopUpButton "Items: Autoenables" autoenablesItems

    版本 11.5 (11E608c),Swift 5.0,DP:macOS 10.15。

    代码:

    import Cocoa
    // 1) Conform to NSMenuItemValidation in the class which implements the NSPopUpButton.
    
    class NSMenuItemValidationTestViewController: NSViewController, NSMenuItemValidation {
    @IBOutlet weak var popupButton: NSPopUpButton!
    
    // MARK: - ViewController lifecycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // .target and .action are set programmatically because menus are mostly build programmatically.
        // 2) All NSMenuItems must have an action and target set to the object which implements the
        // NSMenuItemValidation protocol.
        self.popupButton?.menu?.items.forEach{( $0.target = self )}
        self.popupButton?.menu?.items.forEach{( $0.action = #selector(dummyAction(_:)) )}
    }
    
    // MARK: - NSMenuItemValidation
    // 3) Implement the validateMenuItem(:) method.
    func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
        print("Function: \(#function), line: \(#line)")
        return true
    }
    
    // 4) Implement the dummyAction(:) method for NSMenuItem which doesn't do anything
    @IBAction func dummyAction(_ sender: NSMenuItem?) {
        print("Function: \(#function), line: \(#line)")    }
    
    
    }
    
    // 5) The NSPopUpButton "Items: Autoenables" checkbox must be set to true in storyboard.
    // or
    // self.popupButton?.menu?.autoenablesItems = true
    

    TODO:源代码的 Github 链接。 (即将推出)。

    【讨论】:

      猜你喜欢
      • 2016-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2018-05-01
      相关资源
      最近更新 更多