ControlTextDidChange 不适用于设置 NSTextField 的字符串

Posted

技术标签:

【中文标题】ControlTextDidChange 不适用于设置 NSTextField 的字符串【英文标题】:ControlTextDidChange not working for setting string of NSTextField 【发布时间】:2012-10-29 22:31:20 【问题描述】:

我正在尝试找到一种方法来监视 NSTextField 的文本是否发生变化。我尝试了-(void)controlTextDidChange:(NSNotification *)obj 的委托方法,但它仅在用户输入文本字段时才有效。如果文本字段字符串以编程方式设置,例如使用按钮,controlTextDidChange 不起作用。

有什么方法或其他方法可以用来监控 NSTextField 的内容是否有变化?

我的 ButtonText 类(设置为 NSTextField 的委托):

#import "ButtonText.h"

@interface ButtonText ()

@property (weak) IBOutlet NSTextField *buttonField;

@end

@implementation ButtonText

- (IBAction)buttonTextA:(id)sender 
    [_buttonField setStringValue:@"text A here"];


- (IBAction)buttonTextB:(id)sender 
    [_buttonField setStringValue:@"and text B stuff"];


- (void)controlTextDidChange:(NSNotification *)obj 
    NSLog(@"controlTextDidChange: %@", _buttonField.stringValue);


@end

显示按钮和文本字段的 XIB:

【问题讨论】:

我不知道为什么会这样,但是试试这个,当你以编程方式设置文本时使用[self controlTextDidChange:nil]; @PedroVieira 从IBAction 方法中调用controlTextDidChange,这不是我想要做的。我的目标是最终对文本字段使用绑定并取消 IBAction 方法。所以你的方法不完全是我的想法。不过还是谢谢。 AFAIK 你不应该显式调用委托方法。您可以通过 KVO 和 KVB 轻松完成这项任务。 【参考方案1】:

一种方法是使用 KVO。特别是,将ButtonText 实例添加为buttonFieldstringValue 的观察者。

更详细地说,在您的文件ButtonText 中,一旦设置了@property IBOutlet buttonField(即如果ButtonTextNSWindowController 子类,在-windowDidLoad 中,并且如果ButtonTextNSViewController -loadView) 中的子类,调用

[self.buttonField addObserver:self
                   forKeyPath:@"stringValue"
                      options:0
                      context:&ButtonTextKVOContext];

之前在文件中定义ButtonTextKVOContext如下:

static int ButtonTextKVOContext = 0;

然后如下覆盖observeValueForKeyPath:ofObject:change:context:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

    if (context != &ButtonTextKVOContext) 
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        return;
    

    if (object == self.buttonField) 
        if ([keyPath isEqualToString:@"stringValue"]) 
            NSLog(@"controlTextDidChange: %@", _buttonField.stringValue);
        
    

编辑

由于ButtonText 不是NSWindowControllerNSViewController 的子类,我们将使用稍微不同的方法。和以前一样,我们要开始观察“一旦设置了@property IBOutlet buttonField”。为此,将属性buttonField合成为成员变量mButtonField写作

@synthesize buttonField = mButtonField;

并按如下方式覆盖buttonField的设置器:

- (void)setButtonField:(NSTextField *)buttonField

    [self stopObservingButtonField];
    mButtonField = buttonField;
    [self startObservingButtonField];

我们需要确保ButtonText 在释放时也停止观察按钮字段,因此覆盖-dealloc 如下:

- (void)dealloc

    [self stopObservingButtonField];

剩下的就是定义方法-stopObservingButtonField-startObservingButtonField

- (void)stopObservingButtonField

    if (mButtonField) 
        [mButtonField removeObserver:self
                          forKeyPath:@"stringValue"
                             context:&ButtonTextKVOContext];
    


- (void)startObservingButtonField

    if (mButtonField) 
        [self.buttonField addObserver:self
                           forKeyPath:@"stringValue"
                              options:0
                              context:&ButtonTextKVOContext];
    

由于这种安排,我们绝不能在-setButtonField: 方法之外设置mButtonField 变量。 (这并不完全正确,但如果我们确实设置了mButtonField,我们必须确保首先停止观察其旧值的@"stringValue" 键路径并开始观察其新值的@“stringValue”键路径。这样做而不是而不是简单地调用-setButtonField: 很可能只是构成代码重复并且不值得。)

如需参考,请查看 Apple 的 documentation on the NSKeyValueObserving protocol。

【讨论】:

这就到了。我遇到的唯一问题似乎是我在-(IBAction)buttonTextA:(id)sender 方法中放置的[self.buttonField addObserver:self forKeyPath:...];。这在第一次尝试时效果很好,但如果您继续按下按钮,则会记录多个字符串,而不仅仅是一个字符串。我的ButtonText 类只是一个典型的NSObject 子类。那么我需要将它与NSWindowControllerNSViewController 的子类一起使用吗? 您需要在设置self.buttonField 时开始观察,并在self.buttonField 更改或ButtonText 释放后停止观察。查看我的编辑。 哇,你在这方面做得很深入!无论如何,我通过将[self.buttonField addObserver:self forKeyPath:...]; 放入课堂中的awakeFromNib 方法来使其工作。现在似乎工作正常。我也会尝试您的扩展解决方案。非常感谢您的帮助! 我已经发布了另一个与此相关但使用绑定的问题。您能检查一下问题并再次提供帮助吗?谢谢。 ***.com/questions/13170217/…【参考方案2】:

如果您的目标是使用绑定,那么您可以覆盖已绑定到文本字段值的属性的 setter 方法,并在那里执行您想要执行的任何监控。因此,例如,您有一个文本字段,其值绑定到属性 myText,然后您可以执行以下操作:

-(void)setMyText:(NSString *) newValue 
    _myText= newValue;
    // do monitoring here

只要用户在文本字段中键入或更改代码中的值,只要通过属性而不是直接访问 ivar,都应该调用此方法。

【讨论】:

您能详细说明一下吗?我有点困惑如何准确地使用你的方法。谢谢。 @Gavin 我不确定你想让我详细说明什么。我发布的方法应该放在任何处理与文本字段交互的类中。除此之外,您还没有说明更改文本时要执行的操作,因此我无法进一步详细说明。

以上是关于ControlTextDidChange 不适用于设置 NSTextField 的字符串的主要内容,如果未能解决你的问题,请参考以下文章

为啥 UITableViewAutomaticDimension 不适用于 sectionFooterHeight?

为啥排序不适用于矢量?

验证不适用于 saveMany

UipanGesture 不适用于 Uiswitch

jQuery 不适用于 Express

为啥 MultiBinding 不适用于 CornerRadius