Подавление раскрывающегося списка завершения текста для NSTextField - PullRequest
3 голосов
/ 12 августа 2011

Я пытаюсь создать эффект NSComboBox с completes == ДА, без кнопки и numberOfVisibleItems == 0 (например, попробуйте заполнить альбом или исполнителя в окне «Информация» iTunes) .

Для этого я использую элемент управления NSTextField, который автоматически завершает -controlTextDidChange: для вызова -[NSTextField complete:], что вызывает метод делегата:

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

Я правильно понял, единственная проблема - побочный эффект раскрывающегося списка. Я хотел бы подавить это, но я не видел способа сделать это. Я проверил документацию, Интернет и переполнение стека, но безуспешно.

Я бы предпочел метод делегата, но я открыт для подклассов, если это единственный способ. Я нацеливаюсь на Lion, если это поможет, поэтому решения не должны быть обратно совместимыми.

1 Ответ

4 голосов
/ 19 декабря 2011

Чтобы решить эту проблему, мне пришлось немного нестандартно подумать. Вместо того, чтобы использовать встроенный механизм автозаполнения, я создал свой собственный. Это было не так сложно, как я изначально предполагал. Мой -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;
    }
}

И затем я реализовал другой метод делегата, о котором раньше не знал (так сказать, недостающий фрагмент головоломки).

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

Обновление: упрощенное и исправленное решение

Теперь он не отслеживает последнюю введенную пользователем строку, а определяет, когда пользователь удалил. Это решает проблему прямым, а не окольным путем.

...