NSMenuDelegate方法未调用上下文菜单

时间:2013-06-07 18:32:23

标签: macos cocoa nsmenu

我有一个基于文档的应用程序。我想添加一个上下文菜单,当用户右键单击NSTextView中的所选文本时,该菜单会显示上下文相关信息。

我已遵循Apple documentation

中的建议
  • 在我的XIB文件中添加了NSMenu作为根对象。
  • 将NSMenu实例连接到NSTextView的menu插座。
  • 将IBAction连接到NSMenu内的NSMenuItem。

到目前为止一切顺利。每件事都按预期工作:出现菜单项,并在选择时调用操作。

我需要在菜单出现之前从NSTextView中获取所选文本,以便我可以正确配置我的菜单项。根据文件

  

如果您需要自定义上下文菜单,可以通过设置来完成   一个适当的对象作为菜单的委托并实现   menuWillOpen:如前所述,自定义菜单的方法   它出现了。

我将NSMenu的代表连接到文件的所有者。没有调用任何委托方法。 (menuWillOpen:是我唯一需要的人,但我也尝过其他人。)

我在选择菜单项时调用的IBAction中设置断点。如果我使用调试器检查菜单,我可以看到委托被正确设置为实现委托方法的对象。

还有什么要检查的吗?我有什么明显的错误吗?

Xcode v4.6.3
SDK v10.8
部署目标10.7

2 个答案:

答案 0 :(得分:2)

经过一番挖掘后,我发现了这一点:NSTextView构建了一个不同的NSMenu实例,用作上下文菜单,可能是通过覆盖-menuForEvent:或类似的内部方法。这个新菜单从您在Interface Builder中创建的菜单中复制菜单项(实际上,它创建了从原始菜单项复制属性的新菜单项实例),但它不复制菜单委托,这就是您的菜单委托的原因没有收到-menuWillOpen:。我不确定这是否是故意的。阅读您发布的文档引用,这似乎是一个错误。

您可以做的是将NSTextView实例的委托设置为其类符合NSTextViewDelegate的对象(可能是您的文件所有者,已经符合NSMenuDelegate)并实施以下方法:

- (NSMenu *)textView:(NSTextView *)view menu:(NSMenu *)menu forEvent:(NSEvent *)event atIndex:(NSUInteger)charIndex
{
    // if the menu delegate is not self, set another object
    [menu setDelegate:self];

    return menu;
}

这将确保文本视图创建的上下文菜单使用您的委托。

注意:由于NSTextView创建了不同的上下文菜单,因此可能可能需要将菜单委托设置为自身或其他内部对象。在我的测试中,委托是nil,所以看起来它是安全的。或者,您可以丢弃建议的menu参数并返回您自己的NSMenu实例,并正确设置委托。

答案 1 :(得分:0)

找到这个帖子给我节省了很多时间......谢谢!这是一个适用于Swift NSView的实现。 myNSMenu是故事板到appDelegate的出口,是NSMenu的子类。如果没有在下面的代码中分配委托,则不会调用NSMenuDelegate函数。

    let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate
    appDelegate.myNSMenu.delegate = appDelegate.myNSMenu
    NSMenu.popUpContextMenu(appDelegate.myNSMenu, withEvent: theEvent, forView: self)