NSTokenField not firing action

问题描述:

我有一个NSTokenField将标签添加到对象(文档)。我想在令牌添加到令牌字段(输入令牌字符时)时使用新标签更新对象。不幸的是,这似乎并不奏效。 NSTokenField已连接到我的控制器中的某个操作,但此操作方法从未被调用。NSTokenField not firing action

我也有一个NSTextField以相同的方式连接到控制器,它的控制器中的动作方法被调用。

我也试图与键值观察:

- (void) awakeFromNib { 
    [tokenField addObserver:self forKeyPath:@"objectValue" options:NSKeyValueObservingOptionNew context:NULL]; 
} 


- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 
    if([object isEqual:tokenField]){ 
     NSLog(@"Tokens changed"); 
    } 
} 

但是当我编程改变标记这个动作只调用。

如何更改tokenField中的令牌?

+1

你可以看看下面的帖子: http://stackoverflow.com/questions/852038/delegate-methods-of-nstextfield-using-nsnotification – 2015-02-09 13:22:48

+0

@DavidMangon谢谢。不幸的是,它不是一个完整的解决方案,因为我需要检测何时添加新的令牌。 ' - (void)textDidChange:(NSNotification *)aNotification'在输入字符时以及添加标记字符时调用。 stringValue不会显示添加的标记化字符,并且通知是相同的。 – 2015-02-09 17:22:42

NSTokenField动作选择器在创建新标签时不会被调用。根据您在界面生成器中进行的设置,您可以在按Enter键结束编辑时调用它(发送仅输入),或者当您以其他方式结束编辑时(发送结束编辑) 。为了得到良好的控制,你需要另一种方法。


出现时tokenising字符添加到令牌场蓝色标签被称为文本附件(的NSTextAttachment实例)。处理标记添加/删除标记字段时的一种方法是跟踪包含在标记字段的基础属性字符串中的这些对象数量的变化。

要访问相关的属性字符串,您需要掌握fieldEditor的layoutManager - 最终提供出现在文本视图中的字符串的对象。一旦掌握了该信息,每次收到controlTextDidChange:消息时,请计算其attributedStringstring表示中的文本附件数。如果这次的数字大于先前计数中记录的数字,则会添加标签。

#import "AppDelegate.h" 

@interface AppDelegate() 

@property (weak) IBOutlet NSWindow *window; 
@property (weak) NSLayoutManager *lm; 
@property (nonatomic) NSUInteger tokenCount; 

@end 

@implementation AppDelegate 

// The text in the fieldEditor has changed. If the number of attachments in the 
// layoutManager's attributedString has changed, either a new tag has been added, 
// or an existing tag has been deleted. 
-(void)controlTextDidChange:(NSNotification *)obj { 
    NSUInteger updatedCount = [self countAttachmentsInAttributedString:self.lm.attributedString]; 
    if (updatedCount > self.tokenCount) { 
     NSLog(@"ADDED"); 
     self.tokenCount = updatedCount; 
    } else if (updatedCount < self.tokenCount) { 
     NSLog(@"REMOVED"); 
     self.tokenCount = updatedCount; 
    } 
} 

// About to start editing - get access to the fieldEditor's layoutManager 
-(BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor { 
    self.lm = [(NSTextView *)fieldEditor layoutManager]; 
    return YES; 
} 

// Iterate through the characters in an attributed string looking for occurrences of 
// the NSAttachmentCharacter. 
- (NSInteger)countAttachmentsInAttributedString:(NSAttributedString *)attributedString { 
    NSString *string = [attributedString string]; 
    NSUInteger maxIndex = string.length - 1; 
    NSUInteger counter = 0; 

    for (int i = 0; i < maxIndex + 1; i++) { 
     if ([string characterAtIndex:i] == NSAttachmentCharacter) { 
      counter++; 
     } 
    } 
    return counter; 
} 

@end 
+0

你从哪里得到这些信息?有没有Apple链接? – 2015-10-13 03:10:18

+0

这个答案不是指任何单一来源;我将它与来自与文本系统有关的各种Apple页面拼凑在一起 - 最值得注意的是文档有关文本布局,归因字符串,当然还有NSTokenField类参考。如果你仔细想想,''NSTokenField''是''NSTextField''的一个子类,所以内容可以是字符串或属性字符串。这显然不只是一个字符串,只剩下一个选项!所有你需要做的事情是弄清楚''NSTextAttachment''实例是如何在属性字符串中表示的,然后你可以对它们进行计数。 – 2015-10-15 11:40:21

的@保罗 - 帕特森的代码端口斯威夫特3:

override func controlTextDidChange(_ obj: Notification) { 
    guard let fieldEditor = self.tokenField.currentEditor() as? NSTextView, 
     let layoutManager = fieldEditor.layoutManager 
     else { return } 

    func countAttachments(attributedString: NSAttributedString) -> Int { 

     let string = attributedString.string as NSString 
     let maxIndex = string.length - 1 
     var counter = 0 

     for i in 0..<maxIndex { 
      if string.character(at: i) == unichar(NSAttachmentCharacter) { 
       counter += 1 
      } 
     } 

     return counter 
    } 

    let currentCount = countAttachments(attributedString: layoutManager.attributedString()) 
    // cache count or act on it directly 
} 

奇怪的是,以下的不产生斯威夫特预期的结果:

layoutManager.attributedString().string 
    .split(by: Character(UnicodeScalar(NSAttachmentCharacter)!)).count 

相反,它在用户未输入时返回0,而在编辑令牌时返回1。

let isEditing = layoutManager.attributedString().string 
    .split(by: Character(UnicodeScalar(NSAttachmentCharacter)!)).count == 1 

随着这两种方法的结合,你可以写一个自定义“并添加/删除令牌”使用状态机的回调。 (尽管如此,我认为这不是一种安全的方法。)

  • 跟踪countAttachments(attributedString:)的令牌计数。
  • 使用isEditing检查...
    1. 如果用户开始添加新笔记(新计数>老伯爵& & isEditing ==真)
    2. 如果用户开始编辑现有的笔记(新计==老伯爵& & isEditing ==真)
    3. 如果用户完成令牌(oldIsEditing ==真& & newIsEditing ==假)