Suppressing the text completion dropdown for an NSTextField

半腔热情 提交于 2019-12-22 09:57:41

问题


I'm trying to create the effect of an NSComboBox with completes == YES, no button, and numberOfVisibleItems == 0 (for an example, try filling in an Album or Artist in iTunes's Get Info window).

To accomplish this, I'm using an NSTextField control, which autocompletes on -controlTextDidChange: to call -[NSTextField complete:], which triggers the delegate method:

- (NSArray *)control:(NSControl *)control
            textView:(NSTextView *)textView
         completions:(NSArray *)words
 forPartialWordRange:(NSRange)charRange
 indexOfSelectedItem:(NSInteger *)index;

I've gotten this working correctly, the only problem being the side effect of a dropdown showing. I would like to suppress it, but I haven't seen a way to do this. I've scoured the documentation, Internet, and Stack Overflow, with no success.

I'd prefer a delegate method, but I'm open to subclassing, if that's the only way. I'm targeting Lion, in case it helps, so solutions don't need to be backward compatible.


回答1:


To solve this, I had to think outside the box a little. Instead of using the built-in autocomplete mechanism, I built my own. This wasn't as tough as I had originally assumed it would be. My -controlTextDidChange: looks like so:

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

And then I implemented another delegate method I wasn't previously aware of (the missing piece of the puzzle, so to speak).

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

Update: Simplified and corrected solution

It now doesn't track the last string the user entered, instead detecting when the user deleted. This solves the problem in a direct, rather than roundabout, manner.



来源:https://stackoverflow.com/questions/7040843/suppressing-the-text-completion-dropdown-for-an-nstextfield

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!