12

任何人都可以建议一种方法来选择NSTextField用户单击它时的所有文本吗?

我确实找到了子类的建议NSTextField,然后使用mouseDownor firstResponder,但现在这超出了我的技能。所以我希望要么有一个更简单的解决方案,要么有人可能会很好地详细说明所需的步骤。

4

5 回答 5

24

没有更简单的解决方案,您需要子类化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 秒后执行此操作,这将延迟到下一次运行事件循环。这意味着将在字段编辑器完全配置后进行选择。

于 2010-02-04T01:16:54.660 回答
6

@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.

于 2015-10-20T21:01:30.037 回答
2

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
    }
}
于 2015-10-13T17:30:39.423 回答
1

我喜欢 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
        }
    }
}
于 2017-05-05T12:10:50.403 回答
0

我知道这是一个老问题,但对于那些可能会遇到这个问题的人来说,这里有一个更新。

覆盖 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
    }
}
于 2019-08-16T07:29:46.010 回答