Objective c 抑制NSTextField的文本完成下拉列表
我正在尝试创建一个带有Objective c 抑制NSTextField的文本完成下拉列表,objective-c,cocoa,macos,autocomplete,nstextfield,Objective C,Cocoa,Macos,Autocomplete,Nstextfield,我正在尝试创建一个带有完成==YES,no按钮和numberOfVisibleItems==0的NSComboBox效果(例如,尝试在iTunes的“获取信息”窗口中填充相册或艺术家) 为了实现这一点,我使用了一个NSTextField控件,它在-controlTextDidChange:上自动完成调用-[NSTextField complete:,这会触发委托方法: - (NSArray *)control:(NSControl *)control textView:(
完成
==YES,no按钮和numberOfVisibleItems
==0的NSComboBox效果(例如,尝试在iTunes的“获取信息”窗口中填充相册或艺术家)
为了实现这一点,我使用了一个NSTextField控件,它在-controlTextDidChange:
上自动完成调用-[NSTextField complete:
,这会触发委托方法:
- (NSArray *)control:(NSControl *)control
textView:(NSTextView *)textView
completions:(NSArray *)words
forPartialWordRange:(NSRange)charRange
indexOfSelectedItem:(NSInteger *)index;
我已经让它正常工作了,唯一的问题是下拉显示的副作用。我想抑制它,但我还没有看到一种方法来做到这一点。我搜索了文档、互联网和堆栈溢出,但没有成功
我更喜欢委托方法,但如果这是唯一的方法,我对子类化持开放态度。我的目标是Lion,以防它有所帮助,所以解决方案不需要向后兼容。要解决这个问题,我必须跳出框框思考一下。我没有使用内置的自动完成机制,而是构建了自己的机制。这并不像我最初想象的那么困难。我的
-controlTextDidChange:
看起来是这样的:
- (void)controlTextDidChange:(NSNotification *)note {
// Without using the isAutoCompleting flag, a loop would result, and the
// behavior gets unpredictable
if (!isAutoCompleting) {
isAutoCompleting = YES;
// Don't complete on a delete
if (userDeleted) {
userDeleted = NO;
} else {
NSTextField *control = [note object];
NSString *fieldName = [self fieldNameForTag:[control tag]];
NSTextView *textView = [[note userInfo] objectForKey:@"NSFieldEditor"];
NSString *typedText = [[textView.string copy] autorelease];
NSArray *completions = [self comboBoxValuesForField:fieldName
andPrefix:typedText];
if (completions.count >= 1) {
NSString *completion = [completions objectAtIndex:0];
NSRange difference = NSMakeRange(
typedText.length,
completion.length - typedText.length);
textView.string = completion;
[textView setSelectedRange:difference
affinity:NSSelectionAffinityUpstream
stillSelecting:NO];
}
}
isAutoCompleting = NO;
}
}
然后我实现了另一个我以前没有意识到的委托方法(可以说是拼图中缺失的部分)
更新:简化和更正的解决方案
它现在不跟踪用户输入的最后一个字符串,而是检测用户何时删除。这以直接而非迂回的方式解决了问题。userDeleted和isAutoCompleting之间没有相关的区别。您可以通过将这两个属性合并为一个属性来进一步简化代码。当用户按下delete键时,此代码不提供任何自动完成功能。这与iTunes的工作方式相同
isAutoCompleting
通过禁止在控件文本更改时重新进入函数来防止无限循环。我想说的是,它们最终都实现了相同的目标:当isAutoCompleting为YES时,您不完成。当userDeleted为YES时,您也不会完成。你也可以使用一个变量“inhibitCompletion”,当你将isAutoCompleting或UserDelete设置为YES时,将其设置为YES,并用更少的代码和检查获得相同的净效果。啊,我明白你的意思。但他们在不同的时间仍然被设置为“否”userDeleted
在输入一个字符后关闭,而isAutoCompleting
仅在文本字段的值更新后关闭。我不是说你不能重写它,只使用一个变量,但重点是什么?不自动完成有两个语义原因,上面的代码清楚地说明了这一点。
- (BOOL)control:(NSControl *)control
textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector {
// Detect if the user deleted text
if (commandSelector == @selector(deleteBackward:)
|| commandSelector == @selector(deleteForward:)) {
userDeleted = YES;
}
return NO;
}