我已将基于非文档的 macOS 应用程序的大部分核心功能移至自定义的嵌入式框架。
应用程序代码有一个带有初始窗口的标准主故事板,并且该窗口具有“窗口内容”关系/连接到指向嵌入式框架内的故事板的故事板引用。其中有一个自定义NSViewController
子类和一个自定义NSView
子类。
我想在框架内对所有输入事件处理代码进行分组,这意味着mouseDown(with:)
在自定义NSView
子类上实现,并且--lo 并且看-- 当我在应用程序窗口内单击时它会被调用。到目前为止,一切都很好。
接下来,我实现keyDown(with:)
了类似地处理键盘输入。但是,在运行时,它不会被调用,而是会听到烦人的哔哔声 ( NSBeep
)。
我尝试keyDown(with:)
在视图控制器上实现,但都是一样的。
最后,我尝试在我的NSWindowController
子类上实现密钥处理程序,并且确实有效。
所以我可以通过转发事件来解决这个问题:
class WindowController: NSWindowController {
override func keyDown(with event: NSEvent) {
contentViewController?.view.keyDown(with: event)
}
}
,但它非常不雅。我宁愿不要用输入逻辑污染应用程序代码。
然而,这似乎与嵌入框架没有任何关系。我从“Cocoa App”模板中整理了一个最小的项目,并确认确实keyDown(with:)
只有在窗口控制器代码上实现才被调用,而不是在视图或视图控制器端。
在基于情节提要的应用程序中,如何keyDown(with:)
在视图或视图控制器(而不是窗口或窗口控制器)上被调用?(所以我可以将它从主应用程序移动到我的嵌入式框架)。
编辑:该问题已被标记为重复。我尝试了另一个问题的答案中指出的解决方案(即覆盖acceptsFirstResponder
返回true
)。这解决了我最小的演示项目中的问题,但是当我在我的完整应用程序上尝试它时,它仍然不起作用(我确实看到了那个问题,并且acceptsFirstResponder
在发布这个问题之前确实尝试在我的应用程序中覆盖)。
我现在将尝试修改我的最小诗歌,看看我是否可以在主应用程序中重现该问题。
编辑 2:我已将最小项目重构为:
- 将视图控制器发送到单独的故事板,
- 将视图控制器的故事板和表示的类(自定义视图、自定义视图控制器)发送到单独的嵌入式框架。
现在基本设置反映了我的应用程序似乎很重要的所有设置,但仍然无法在最小项目中重现该问题。我会进一步调查...
编辑 3:我无法在最小项目上重现该问题。在我的应用程序的自定义视图中,我实现了:
public override var acceptsFirstResponder: Bool {
return true
}
public override func performKeyEquivalent(with event: NSEvent) -> Bool {
let retVal = super.performKeyEquivalent(with: event)
return retVal
}
- 在启动时,
acceptsFirstResponder
被调用两次。 - 按下任何键时,
performKeyEquivalent(with:)
也会调用两次。检查上面的中间变量retVal
表明超类的实现总是返回false
。从这个方法返回后,NSBeep()
被调用而keyDown(with:)
不是被调用。 - 如果不是
super.performKeyEquivalent(with:)
I force-returntrue
,我可以避免调用NSBeep()
(但keyDown(with:)
仍然没有调用...)
编辑 4(最终):
出于绝望,我在我的应用程序的主故事板中清除了窗口控制器的身份检查器的“自定义类”字段(默认NSWindowController
)。
突然,我的自定义视图keyDown(with:)
开始被调用。
我恢复了自定义类以确认。
它仍然有效。
我清理构建文件夹并重试。
它仍然有效。
现在,即使在我的主应用程序上,我也无法再重现该问题。我真的不知道该说什么...