我有NSTokenField
向对象(文档)添加标签。我想在将令牌添加到令牌字段时(当键入令牌化字符时)使用新标签更新对象。不幸的是,这似乎不起作用。
NSTokenField
连接到我的控制器中的操作,但从不调用此操作方法。
我也有一个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
中的令牌发生变化,我该如何收到通知?
答案 0 :(得分:7)
创建新标记时不会调用NSTokenField
操作选择器。根据您在 Interface Builder 中使用的设置,当您按Enter键进行结束编辑(仅限输入)或结束编辑时,可以调用它其他方式(发送结束编辑)。为了获得良好的控制,你需要采取另一种方法。
将令牌字符添加到令牌字段时出现的蓝色标记称为文本附件(NSTextAttachment
的实例)。在令牌字段中添加/删除标记时,一种计算方法是跟踪令牌字段的基础属性字符串中包含的这些对象数量的更改。
要访问相关的属性字符串,您需要获取 fieldEditor的 layoutManager
- 最终提供文本视图中显示的字符串的对象。获得此消息后,每次收到controlTextDidChange:
消息时,请计算其string
的{{1}}表示中的文本附件数。如果此时间的数字大于前一次计数中记录的数字,则刚刚添加了一个标记。
attributedString
答案 1 :(得分:1)
@ paul-patterson代码到Swift 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
}
奇怪的是,以下不在Swift中产生了预期的结果:
layoutManager.attributedString().string
.split(by: Character(UnicodeScalar(NSAttachmentCharacter)!)).count
相反,它在用户未键入时返回0,在编辑令牌时返回1。
let isEditing = layoutManager.attributedString().string
.split(by: Character(UnicodeScalar(NSAttachmentCharacter)!)).count == 1
通过两种方法的结合,您可以编写自定义&#34;添加/删除令牌&#34;使用状态机回调。 (但我并不认为这是一种非常安全的方式来实现它。)
countAttachments(attributedString:)
跟踪令牌的数量。isEditing
检查...