2

我有一个带有一些 NSTextFields 的 Mac 应用程序(SDK 10.10):

xib文件

由于我需要在文本字段获得和退出焦点时得到通知,因此我将 NSTextField 子类化:

@interface MyTextField : NSTextField
@end

@implementation MyTextField

- (BOOL)becomeFirstResponder
{
    BOOL didBecomeFirstResponder = [super becomeFirstResponder];
    NSLog(@"%@ didBecomeFirstResponder = %@", [self accessibilityLabel], didBecomeFirstResponder?@"YES":@"NO");
    return didBecomeFirstResponder;
}

- (BOOL)resignFirstResponder
{
    BOOL didResignFirstResponder = [super resignFirstResponder];
    NSLog(@"%@ didResignFirstResponder = %@", [self accessibilityLabel], didResignFirstResponder?@"YES":@"NO");
    return didResignFirstResponder;
}

@end

运行此代码并在 3 个文本字段之间切换时,我在控制台中得到以下输出:

firstField didResignFirstResponder = YES
firstField didBecomeFirstResponder = YES
secondField didResignFirstResponder = YES
secondField didBecomeFirstResponder = YES
thirdField didResignFirstResponder = YES
thirdField didBecomeFirstResponder = YES
firstField didResignFirstResponder = YES
firstField didBecomeFirstResponder = YES
secondField didResignFirstResponder = YES
secondField didBecomeFirstResponder = YES

每次我按 TAB 键(或单击其中一个非活动文本字段)时,应用程序都会输出

<new first responder> didResignFirstResponder = YES
<new first responder> didBecomeFirstResponder = YES

那不应该是

<old first responder> didResignFirstResponder = YES
<new first responder> didBecomeFirstResponder = YES

???

我这里有什么大错特错吗?

的文档- (BOOL)resignFirstResponder

通知接收者它被要求在其窗口中放弃其作为第一响应者的状态。

那么为什么会resignFirstResponder召唤新的第一响应者而不是旧的第一响应者呢?

4

2 回答 2

1

我遇到了同样的问题并且找不到解决方案,所以我最终解决了这个问题并使用textDidEndEditing()了相同目的的方法。SWIFT代码:

MyTextField子类NSTextField并向其添加myDelegate属性,该属性应在文本字段失去焦点后处理逻辑。

class MyTextField : NSTextField
{

/// Custom delegate with other methods than NSTextFieldDelegate.
var myDelegate: MyTextFieldDelegate? = nil;

override func becomeFirstResponder() -> Bool {
    let became = super.becomeFirstResponder();
    if (became) {
        self.myDelegate?.myTextFieldDidBecomeFirstResponder(self);
    }
    return became;
}

override func resignFirstResponder() -> Bool {
    let resigned = super.resignFirstResponder();
    if (resigned) {
        self.myDelegate?.myTextFieldDidResignFirstResponder(self);
    }
    return resigned;
}

override func textDidEndEditing(obj: NSNotification) {
    super.textDidEndEditing(obj);
    self.myDelegate?.myTextFieldDidResignFirstResponder(self);
}

}

协议本身:

protocol MyTextFieldDelegate
{

    func myTextFieldDidBecomeFirstResponder(textField: MyTextField);

    func myTextFieldDidResignFirstResponder(textField: MyTextField);
}

显然,您可以在此处实现丢失/获得焦点逻辑,而不是使用和调用委托(例如绘制不同的边框等)。

线索是textDidEndEditing()方法,当我单击另一个字段、按 Enter 或 Tab 退出时,它似乎可以正常工作。

于 2015-05-26T16:29:22.897 回答
1

Apple 开发者论坛上的某个人解释了为什么它的行为如此:

当文本字段具有焦点时,它们实际上并不是第一响应者。Cocoa 创建了一个特殊的文本视图,称为字段编辑器,并临时将其添加到视图层次结构中,覆盖文本字段。它使该文本视图成为第一响应者。这个文本视图是处理所有用户交互的。

来源:https ://forums.developer.apple.com/thread/109158#339676

 

解决方法

覆盖该方法(由 Michał 在此答案textDidEndEditing:中提到)是最好的解决方案,IMO。

如果不想子类NSTextField化,就创建一个符合NSTextFieldDelegate协议并实现controlTextDidEndEditing:方法的类。然后,设置实例的delegate属性。NSTextField

最后,您可以覆盖子类的fieldEditor:forObject:方法NSWindow。但是这种方法实际上没有正式的文档(我可以找到)。

要了解有关“字段编辑器”的更多信息,请阅读以下文章:

于 2019-02-15T01:19:21.780 回答