有谁知道防止逃生键关闭的最佳方法?NSPanel
当它是键窗口的时候?我的面板是一个子窗口,我希望它的行为更像窗口的半永久部分,更像一个抽屉,对于其中的文本控件,我希望Escape键取消编辑。
最近我在Cocoa文档中发现了更多关于窗口和Escape键的内容。在NSResponder类参考下 cancelOperation:
其中写道:"窗口会发送一个默认的操作消息,即 cancelOperation:
到第一个响应者,然后信息从那里向上传递到响应者链"。这似乎是不同的。NSPanel
窗口关闭时,第一反应者没有得到 cancelOperation:
调用或NSTextView委托人获得他们的 doCommandBySelector:
呼叫。
考虑到我做OS X工作的时间,我对应答器链的in's &out's的了解是可耻的。我在想,我需要让 keyDown:
在我 NSPanel
子类的行为就像普通窗口一样。我试着覆盖了 NSPanel
并能抓住 keyDown:
,将电话转接到 NSWindow
's keyDown:
而不是 super
,但没有任何变化,逃逸还是关闭了窗口,没有消息给第一反应人。这样的尝试合理吗?
然后,我尝试完全重新实现我的面板子类的 keyDown:
,使它这样做。
[self.firstResponder cancelOperation:self]
我认为这样做可以让我的文本字段按照正常的方式处理转义 如果没有文本字段是第一个响应者的话,那么呼叫就会结束。然而,我试了一下,面板只是像以前一样关闭。显然,我没有在正确的层次上拦截事情。
有谁知道在低级别的按键事件和面板关闭之间运行的方法顺序是什么,或者我需要覆盖什么来拦截它并确保。cancelOperation:
去我的第一反应者?
在你的nib或代码中的某个地方,设置你的NSTableView委托给你的控制器。
注意,setDelegate:和setDatasource:是不一样的!
在我的例子中。 @interface ValueEditor : NSObject (NSObject)
+ (ValueEditorCmdType)cmdTypeForSelector:(SEL)command
{
ValueEditorCmdType cmdType = kCmdTypeNone;
if ( command == @selector(insertLineBreak:) || command == @selector(insertNewline:) || command == @selector(insertNewlineIgnoringFieldEditor:) || command == @selector(insertParagraphSeparator:))
cmdType = kCmdTypeAccept;
else if ( command == @selector(insertTab:) || command == @selector(selectNextKeyView:) || command == @selector(insertTabIgnoringFieldEditor:))
cmdType = kCmdTypeNext;
else if ( command == @selector(insertBacktab:) || command == @selector(selectPreviousKeyView:))
cmdType = kCmdTypePrev;
else if ( command == @selector(cancelOperation:) )
cmdType = kCmdTypeCancel;
return cmdType;
}
#pragma mark - NSControl delegate
- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
{
ValueEditorCmdType cmdType = [ValueEditor cmdTypeForSelector:command];
if ( cmdType == kCmdTypeCancel )
{
[control abortEditing];
// when user hits 'ESC' key with a field editor active, cancel the field editor,
// but return YES here so that NSPanel doesn't close.
// Hitting 'ESC' a 2nd time will close the NSPanel.
return YES;
}
return NO;
}
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对象的委托人!