有人知道在钥匙窗口时阻止逃脱键关闭NSPanel
的最佳方法吗?我的面板是一个子窗口,我希望它的行为更像窗口的半永久部分,更像是抽屉,对于其中的文本控件,我想拥有逃生键取消编辑。
我最近在可可文档中找到了有关Windows和逃生密钥的更多信息。在cancelOperation:
下的NSResponder类参考中,其中说:"窗口将cancelOperation:
的默认操作消息发送给第一响应者,从那里传播响应者链的消息"。NSPanel
似乎有所不同,窗口关闭而没有第一响应者获取cancelOperation:
呼叫或NSTEXTVIEW代表获得doCommandBySelector:
呼叫。
我对In&考虑到我一直在做OS X的工作,OUT的响应链链条是可耻的。我以为我需要在NSPanel
子类中制作keyDown:
,就像普通窗口一样。我尝试覆盖NSPanel
并可以捕获keyDown:
,将呼叫转发到NSWindow
的keyDown:
而不是super
,但没有变化,但逃脱仍然没有给第一响应者的消息关闭窗口。这是合理的尝试吗?
然后,我试图完全重新进化我的面板子类的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对象的代表!
在您的笔尖或代码中的某个地方,将您的NstableView委托设置为控制器。
请注意,setDelegate:与setDataSource不同:!
在我的情况下: @interface valueeditor: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;
}