从 NSCollectionView 获取当前焦点的文档对象
Get document object with current focus from NSCollectionView
我打开了一个(子类)NSCollectionView,其中包含多个文本视图。每个文本视图都映射到一个(子类)NSDocument 对象。 (想法是使用文档架构的保存功能而不是它的 windowing 功能,因为我需要在同一个 window 中使用多个文档,而传统的文档架构不允许这样做。)
现在,我希望用户能够从主菜单调用一个功能,该功能会影响他们当前选择的文档。也就是说:该文档当前在具有当前焦点的文本视图中可见,并且菜单命令应该对该文档进行更改。但是菜单命令的发送者只是菜单。当 window 控制器处理来自菜单的命令时,我如何告诉它当前选择的文档是什么?
这就是 the responder chain 的用途。
由于您正在使用 NSCollectionView
,您可能已经拥有 NSCollectionViewItem
的子class。如果没有,请创建一个。在此 subclass 中实现您的操作方法。示例:
class DocumentItem: NSCollectionViewItem {
var document: MyDocument? {
return representedObject as? MyDocument
}
@IBAction func doThatThing(sender: AnyObject?) {
Swift.print("This is where I do that thing to \(document)")
}
// @IBOutlets and whatnot here...
}
您可能需要在 xib 或故事板中将其设置为 NSCollectionViewItem
的自定义 class。
接下来,如果您的单元格视图(您的 NSCollectionViewItem
拥有的视图)已经不是 NSView
的自定义子class,您应该将其设为自定义子class。您必须将 acceptsFirstResponder
覆盖为 return true:
class DocumentCellView: NSView {
override var acceptsFirstResponder: Bool { return true }
// @IBOutlets and whatnot here...
}
确保在故事板或 xib 中将此设置为单元格视图的自定义 class。
最后,将菜单项的操作连接到 First Responder 上的 doThatThing:
:
工作原理如下:
因为单元格视图现在 return对于 acceptsFirstResponder
为真,当用户单击集合视图中的单元格视图时,系统会将其设为 第一响应者(响应者链的开始)。
当一个视图有一个视图控制器时,它使该视图控制器成为响应者链中其自身之后的下一个响应者(如果您使用 OS X 10.10 Yosemite 或更高版本)。您的单元格视图有一个视图控制器:您 return 来自 outlineView:itemForRepresentedObjectAtIndexPath:
的项目对象。 (NSCollectionViewItem
是 NSViewController
的子 class,因此您的自定义项是视图控制器。)
当用户单击菜单项时,菜单项要求 NSApplication
沿着响应者链发送它的操作,从第一个响应者开始。第一响应者是单元格视图,但它不响应 doThatThing:
消息。所以 NSApplication
向视图询问它的 nextResponder
,它是你的 NSCollectionViewItem
subclass 的一个实例。该对象 确实 响应 doThatThing:
,因此 NSApplication
将 doThatThing:
发送到您的项目对象(使用 NSMenuItem
对象作为 sender
参数)并且不检查响应链的其余部分。
我打开了一个(子类)NSCollectionView,其中包含多个文本视图。每个文本视图都映射到一个(子类)NSDocument 对象。 (想法是使用文档架构的保存功能而不是它的 windowing 功能,因为我需要在同一个 window 中使用多个文档,而传统的文档架构不允许这样做。)
现在,我希望用户能够从主菜单调用一个功能,该功能会影响他们当前选择的文档。也就是说:该文档当前在具有当前焦点的文本视图中可见,并且菜单命令应该对该文档进行更改。但是菜单命令的发送者只是菜单。当 window 控制器处理来自菜单的命令时,我如何告诉它当前选择的文档是什么?
这就是 the responder chain 的用途。
由于您正在使用 NSCollectionView
,您可能已经拥有 NSCollectionViewItem
的子class。如果没有,请创建一个。在此 subclass 中实现您的操作方法。示例:
class DocumentItem: NSCollectionViewItem {
var document: MyDocument? {
return representedObject as? MyDocument
}
@IBAction func doThatThing(sender: AnyObject?) {
Swift.print("This is where I do that thing to \(document)")
}
// @IBOutlets and whatnot here...
}
您可能需要在 xib 或故事板中将其设置为 NSCollectionViewItem
的自定义 class。
接下来,如果您的单元格视图(您的 NSCollectionViewItem
拥有的视图)已经不是 NSView
的自定义子class,您应该将其设为自定义子class。您必须将 acceptsFirstResponder
覆盖为 return true:
class DocumentCellView: NSView {
override var acceptsFirstResponder: Bool { return true }
// @IBOutlets and whatnot here...
}
确保在故事板或 xib 中将此设置为单元格视图的自定义 class。
最后,将菜单项的操作连接到 First Responder 上的 doThatThing:
:
工作原理如下:
因为单元格视图现在 return对于 acceptsFirstResponder
为真,当用户单击集合视图中的单元格视图时,系统会将其设为 第一响应者(响应者链的开始)。
当一个视图有一个视图控制器时,它使该视图控制器成为响应者链中其自身之后的下一个响应者(如果您使用 OS X 10.10 Yosemite 或更高版本)。您的单元格视图有一个视图控制器:您 return 来自 outlineView:itemForRepresentedObjectAtIndexPath:
的项目对象。 (NSCollectionViewItem
是 NSViewController
的子 class,因此您的自定义项是视图控制器。)
当用户单击菜单项时,菜单项要求 NSApplication
沿着响应者链发送它的操作,从第一个响应者开始。第一响应者是单元格视图,但它不响应 doThatThing:
消息。所以 NSApplication
向视图询问它的 nextResponder
,它是你的 NSCollectionViewItem
subclass 的一个实例。该对象 确实 响应 doThatThing:
,因此 NSApplication
将 doThatThing:
发送到您的项目对象(使用 NSMenuItem
对象作为 sender
参数)并且不检查响应链的其余部分。