3

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

我已遵循Apple 文档中的建议,并且

  • 在我的 XIB 文件中添加了一个 NSMenu 作为根对象。
  • 将 NSMenu 实例连接到 NSTextView 的menu出口。
  • 将 IBAction 连接到 NSMenu 内的 NSMenuItem。

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

我需要在菜单出现之前从 NSTextView 获取选定的文本,以便我可以适当地配置我的菜单项。根据文档

如果您需要自定义上下文菜单,您可以通过将适当的对象设置为菜单的委托并实现 menuWillOpen: 方法来自定义菜单,以便在它出现之前按照您认为合适的方式自定义菜单。

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

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

还有什么要检查的吗?我做错了什么?

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

4

2 回答 2

3

经过一番挖掘,这就是我发现的: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实例并正确设置委托。

于 2013-06-07T19:32:33.953 回答
0

找到这个线程为我节省了很多时间......谢谢!这是一个NSView在 Swift 中运行的实现。myNSMenu是 Storyboard 的一个出口,appDelegate也是NSMenu. 如果没有在下面的代码中分配委托,NSMenuDelegate则不会调用函数。

    let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate
    appDelegate.myNSMenu.delegate = appDelegate.myNSMenu
    NSMenu.popUpContextMenu(appDelegate.myNSMenu, withEvent: theEvent, forView: self)        
于 2016-04-28T15:59:57.887 回答