2015-02-08 162 views
2

我有一個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

回答

6

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

0

的@保羅 - 帕特森的代碼端口斯威夫特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 ==假)