任何人都可以建议一种方法来选择NSTextField
用户单击它时的所有文本吗?
我确实找到了子类的建议NSTextField
,然后使用mouseDown
or firstResponder
,但现在这超出了我的技能。所以我希望要么有一个更简单的解决方案,要么有人可能会很好地详细说明所需的步骤。
任何人都可以建议一种方法来选择NSTextField
用户单击它时的所有文本吗?
我确实找到了子类的建议NSTextField
,然后使用mouseDown
or firstResponder
,但现在这超出了我的技能。所以我希望要么有一个更简单的解决方案,要么有人可能会很好地详细说明所需的步骤。
没有更简单的解决方案,您需要子类化NSTextField
来做您想做的事。如果您要在 Cocoa 中做任何有用的事情,您将需要学习如何处理子类化。
文本字段的子类化可能相对复杂,因为NSTextField
使用称为字段编辑器的单独NSTextView
对象来处理实际编辑。此文本视图由 的NSWindow
对象返回,NSTextField
并重新用于页面上的所有文本字段。
像任何子NSResponder
类一样,NSTextField
响应方法-acceptsFirstResponder
和-becomeFirstResponder
. 当窗口想要将焦点赋予特定控件或视图时调用这些函数。如果您YES
从这两种方法中返回,那么您的控件/视图将具有第一响应者状态,这意味着它是活动控件。但是,如前所述,NSTextField 实际上会在单击时为字段编辑器提供第一响应者状态,因此您需要在NSTextField
子类中执行以下操作:
@implementation MCTextField
- (BOOL)becomeFirstResponder
{
BOOL result = [super becomeFirstResponder];
if(result)
[self performSelector:@selector(selectText:) withObject:self afterDelay:0];
return result;
}
@end
这首先调用超类的实现,-becomeFirstResponder
它将完成管理字段编辑器的艰苦工作。然后它调用-selectText:
which 选择字段中的所有文本,但它会在延迟 0 秒后执行此操作,这将延迟到下一次运行事件循环。这意味着将在字段编辑器完全配置后进行选择。
@Rob 的答案可能在某一时刻有效,但正如@Daniel 指出的那样,它不再有效。看起来 Cocoa 想要跟踪鼠标并拖出一个选择来响应点击,而尝试选择文本来响应becomeFirstResponder
并不能很好地发挥作用。
然后,需要拦截鼠标事件以防止跟踪。通过反复试验或多或少,我找到了一个似乎适用于 OS X 10.10 的解决方案:
@interface MyAutoselectTextField : NSTextField
@end
@implementation MyAutoselectTextField
- (void)mouseDown:(NSEvent *)theEvent
{
[[self currentEditor] selectAll:nil];
}
@end
据我所知,当mouseDown:
被调用时,字段编辑器已经设置好了,可能是becomeFirstResponder
. 然后调用selectAll:
选择字段编辑器的内容。调用selectText:
onself
反而效果不好,大概是因为设置了字段编辑器。请注意,mouseDown:
此处的覆盖不会调用super
; super
会运行一个跟踪循环,拖出一个选择,我们不希望这种行为。请注意,mouseDown:
一旦文本字段成为第一响应者,此覆盖不会影响选择,因为此时mouseDown:
将调用字段编辑器。
我不知道这适用于哪些 OS X 版本;如果你在乎,你需要测试它。不幸的是,使用NSTextField
总是有点脆弱,因为字段编辑器的工作方式非常奇怪,并且非常依赖于super
.
Swift 的一些更新:
import Cocoa
class TextFieldSubclass: NSTextField {
override func mouseDown(theEvent: NSEvent) {
super.mouseDown(theEvent)
if let textEditor = currentEditor() {
textEditor.selectAll(self)
}
}
}
或进行精确选择:
import Cocoa
class TextFieldSubclass: NSTextField {
override func mouseDown(theEvent: NSEvent) {
super.mouseDown(theEvent)
if let textEditor = currentEditor() {
textEditor.selectedRange = NSMakeRange(location, length)
}
}
}
Swift 版本,适用于我:
import Cocoa
class TextFieldSubclass: NSTextField {
override func becomeFirstResponder() -> Bool {
let source = CGEventSourceCreate(CGEventSourceStateID.HIDSystemState)
let tapLocation = CGEventTapLocation.CGHIDEventTap
let cmdA = CGEventCreateKeyboardEvent(source, 0x00, true)
CGEventSetFlags(cmdA, CGEventFlags.MaskCommand)
CGEventPost(tapLocation, cmdA)
return true
}
}
我喜欢 Konstantin 的解决方案,但它会在每次鼠标按下时进行选择。这是我用来选择mouseDown
方法的一个变体,但前提是它刚刚成为第一响应者:
class SelectingTextField: NSTextField {
var wantsSelectAll = false
override func becomeFirstResponder() -> Bool {
wantsSelectAll = true
return super.becomeFirstResponder()
}
override func mouseDown(with event: NSEvent) {
super.mouseDown(with: event)
if wantsSelectAll {
selectText(self)
wantsSelectAll = false
}
}
}
我知道这是一个老问题,但对于那些可能会遇到这个问题的人来说,这里有一个更新。
覆盖 NSTextField 并挂接到 becomeFirstResponder()。您不必担心管理委托或点击。棘手的部分是首先找到焦点文本字段的字段编辑器,然后再要求它选择所有文本。
Objective-C
// in AutoselectOnFocusTextField.h
@interface AutoselectOnFocusTextField : NSTextField
@end
// in AutoselectOnFocusTextField.m
@implementation AutoselectOnFocusTextField
- (BOOL)becomeFirstResponder {
if (![super becomeFirstResponder]) {
return NO;
}
NSText* fieldEditor = [self currentEditor];
if (fieldEditor != nil) {
[fieldEditor performSelector:@selector(selectAll:) withObject:self afterDelay:0.0];
}
return YES;
}
@end
迅速
class AutoselectOnFocusTextField: NSTextField {
override func becomeFirstResponder() -> Bool {
guard super.becomeFirstResponder() else {
return false
}
if let editor = self.currentEditor() {
editor.perform(#selector(selectAll(_:)), with: self, afterDelay: 0)
}
return true
}
}