有谁知道防止转义键关闭 NSPanel
当它是关键窗口时的最佳方法?我的面板是一个子窗口,我希望它的行为更像窗口的半永久部分,更像一个抽屉,对于其中的文本控件,我希望使用 Escape 键取消编辑。
我最近在 Cocoa 文档中发现了有关 Windows 和 Escape 键的更多信息。在 cancelOperation:
下的 NSResponder 类引用中,它表示“窗口将 cancelOperation:
的默认操作消息发送到第一个响应者,然后消息从那里沿着响应者链向上传播” 。对于 NSPanel
来说似乎有所不同,窗口关闭时没有第一个响应者获得 cancelOperation:
调用或 NSTextView 委托(delegate)获得他们的 doCommandBySelector:
打电话。
考虑到我一直在做 OS X 工作,我对响应者链的进出的了解是可耻的。我想我需要让我的 NSPanel 子类中的 keyDown: 表现得像普通窗口一样。我尝试覆盖 NSPanel
并可以捕获 keyDown:
,将调用转发到 NSWindow
的 keyDown:
而不是super
,但是没有任何变化,Escape仍然关闭了窗口,没有向第一响应者发送消息。这样的尝试是否合理?
然后我尝试完全重新实现我的面板子类'keyDown:
,使其执行以下操作:
[self.firstResponder cancelOperation:self]
我认为这会让我的文本字段按照通常预期的方式处理转义,也许如果没有文本字段是第一响应者,那么调用就会死胡同。然而,我尝试了一下,面板就像以前一样简单地关闭了。显然我没有在正确的级别拦截东西。
有谁知道在低级按键事件和面板关闭之间运行的方法序列是什么,或者我需要重写什么来拦截它并确保 cancelOperation:
进入我的第一响应者?
最佳答案
keith-knauber 答案的快速移植:
class ValueEditor : NSObject, NSControlTextEditingDelegate {
enum CommandType {
case none
case accept
case next
case prev
case cancel
}
class func commandTypeType(for command: Selector) -> CommandType {
let commandType: CommandType
switch command {
case #selector(NSStandardKeyBindingResponding.insertLineBreak(_:)) :
fallthrough
case #selector(NSStandardKeyBindingResponding.insertNewline(_:)) :
fallthrough
case #selector(NSStandardKeyBindingResponding.insertNewlineIgnoringFieldEditor(_:)) :
fallthrough
case #selector(NSStandardKeyBindingResponding.insertParagraphSeparator(_:)) :
commandType = .accept
case #selector(NSStandardKeyBindingResponding.insertTab(_:)) :
fallthrough
case #selector(NSWindow.selectNextKeyView(_:)) :
fallthrough
case #selector(NSStandardKeyBindingResponding.insertTabIgnoringFieldEditor(_:)) :
commandType = .next
case #selector(NSStandardKeyBindingResponding.insertBacktab(_:)) :
fallthrough
case #selector(NSWindow.selectPreviousKeyView(_:)) :
commandType = .prev
case #selector(NSStandardKeyBindingResponding.cancelOperation(_:)) :
commandType = .cancel
default:
commandType = .none
}
return commandType
}
// MARK: - NSControl delegate
func control(_ control: NSControl,
textView: NSTextView,
doCommandBy commandSelector: Selector) -> Bool {
let commandType: CommandType = ValueEditor.commandTypeType(for: commandSelector)
switch commandType {
case .cancel:
control.abortEditing()
// When the user hits 'ESC' key with a field editor active, cancel the field editor,
// but return `true` here so that the NSPanel doesn’t close.
// Hitting 'ESC' a second time will close the NSPanel.
return true
default:
return false
}
}
}
不要忘记将 ValueEditor 实例设置为 NSTextView 对象的委托(delegate)!
关于cocoa - 防止 Escape 键通过关闭框关闭 NSPanel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12965798/