【发布时间】:2020-02-05 05:17:18
【问题描述】:
如何判断一个 NSSearchField/NSTextField 是否有输入焦点?
【问题讨论】:
-
我的回答实际上是不正确的。我已经对其进行了编辑,以便您可以删除复选标记。请参阅 Greg Titus 的回答。
如何判断一个 NSSearchField/NSTextField 是否有输入焦点?
【问题讨论】:
前面的答案是错误的,因为NSTextField / NSSearchField 本身并没有成为第一响应者并处理编辑的文本。相反,他们使用窗口的字段编辑器,这是一个NSTextView,在窗口上的所有字段之间共享(因为一次只能有一个字段具有焦点)。
您需要查看第一响应者是否为NSText,如果是,则搜索字段/文本字段是否为其代表。
NSResponder *firstResponder = [[NSApp keyWindow] firstResponder];
if ([firstResponder isKindOfClass:[NSText class]] && [(id)firstResponder delegate] == mySearchField) {
NSLog(@"Yup.");
}
【讨论】:
delegate 返回id。
虽然 Greg Titus 的回答可能有效,但我认为以下是更好的方法:
BOOL isFirstResponder = mySearchField.currentEditor == mySearchField.window.firstResponder;
【讨论】:
AppKit 使用“字段编辑器”(NSTextView)来处理NSTextField(或NSSearchField 或NSSecureTextField)中的实际编辑。虽然您的文本字段的窗口具有键盘焦点,但它具有作为子视图的字段编辑器,并且窗口的第一响应者是字段编辑器。
所以一般情况下,你可以检查文本字段是否有字段编辑器:
if textField.currentEditor() != nil {
// textField has the keyboard focus
} else {
// textField does not have the keyboard focus
}
但是,当您将焦点移出文本字段时(通过按 Tab 键或单击另一个文本字段),该文本字段会发布 NSControl.textDidEndEditingNotification(Objective-C:@ 987654327@)。如果文本字段有一个委托,并且该委托实现了NSControlTextEditingDelegate协议的control(_:controlTextDidEndEditing:)方法,那么该通知也会调用该委托方法。
在传递此通知时(包括调用委托方法),文本字段仍将字段编辑器作为子视图,并且字段编辑器的委托仍设置为文本字段。因此,如果您不想在通知处理程序(或委托方法)中考虑文本字段仍然具有键盘焦点,那么测试字段编辑器将给出错误的答案。
(你可能认为这是一个奇怪的测试,因为毕竟 AppKit 向你发送了一个通知,文本字段不再是键盘焦点,所以你为什么需要问?但也许你的通知处理程序调用其他一些想要检查的方法,并且您不想传递一个标志,上面写着“哦,顺便说一下,文本字段现在是/不是键盘焦点”。)
好吧,无论如何,在发送NSControl.textDidEndEditingNotification 之前,AppKit 会更改文本字段的窗口的第一响应者。因此,您可以检查文本字段是否具有字段编辑器,以及该字段编辑器是否是其窗口的第一响应者。当您处理 NSControl.textDidEndEditingNotification 时,此测试将报告文本字段没有键盘焦点。
extension NSTextField {
public var hasKeyboardFocus: Bool {
guard
let editor = currentEditor(),
editor == window?.firstResponder
else { return false }
return true
}
}
【讨论】:
NSSearchField 是NSTextField 的子类。
controlTextDidChange、controlTextDidEndEditing 和controlTextDidBeginEditing 中使用它。在所有情况下,它总是报告搜索字段是焦点。检查textField.currentEditor() == nil 是否需要注册NSControl.textDidEndEditingNotification 也是如此。如果是这样,我该怎么做?