3 Stimmen

Unterdrückung der Textvervollständigungsliste für ein NSTextField

Ich versuche, den Effekt einer NSComboBox zu erzeugen mit completes == YES, keine Taste, und numberOfVisibleItems == 0 (als Beispiel können Sie versuchen, ein Album oder einen Interpreten in das iTunes-Fenster "Get Info" einzugeben).

Um dies zu erreichen, verwende ich ein NSTextField-Steuerelement, das automatisch vervollständigt wird, wenn -controlTextDidChange: anrufen -[NSTextField complete:] die die Delegate-Methode auslöst:

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

Das einzige Problem ist der Nebeneffekt, dass ein Dropdown angezeigt wird. Ich würde es gerne unterdrücken, aber ich habe keine Möglichkeit gesehen, dies zu tun. Ich habe die Dokumentation, das Internet und Stack Overflow durchforstet, ohne Erfolg.

Ich würde eine delegierte Methode bevorzugen, aber ich bin offen für eine Unterklassifizierung, wenn das die einzige Möglichkeit ist. Ich bin Targeting Lion, für den Fall, dass es hilft, so Lösungen müssen nicht abwärtskompatibel sein.

4voto

Dov Punkte 14668

Um dieses Problem zu lösen, musste ich ein wenig über den Tellerrand hinausschauen. Anstatt den eingebauten Autovervollständigungsmechanismus zu verwenden, habe ich mir einen eigenen gebaut. Das war nicht so schwierig, wie ich ursprünglich angenommen hatte. Mein -controlTextDidChange: sieht so aus:

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

Und dann habe ich eine weitere Delegatenmethode implementiert, die ich vorher nicht kannte (sozusagen das fehlende Puzzlestück).

- (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: Vereinfachte und korrigierte Lösung

Jetzt wird nicht mehr die letzte vom Benutzer eingegebene Zeichenkette verfolgt, sondern der Zeitpunkt, an dem der Benutzer gelöscht hat. Damit wird das Problem auf direktem Weg und nicht auf Umwegen gelöst.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X