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;
}