开发者

NSTextField's autocompletion method

I'm having problem triggering complete: method for NSTextfield.

for now I can make an dis开发者_如何转开发tinct array of names from a textfield using @distinctUnionOfObjects ( awesome method to remove duplicates of an array ) and now I can send back autocompletion for this textfield using:

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

But, this method is not automatic and I have to press ESC button to pop the autocompletion suggestion up for the textfield during data entry.

I searched here and found some examples that make no sense for me.

Short Question: Is there any method using NSTexfields delegates like controlDidChanged or something like that to do this more easily and clearly ?

I just confuse using complete: method for nstextview.


I don't recommend copying the whole string. It would be fine for your case, but if you're using autocompletion for a large text file, then you'll have all kinds of performance and memory issues. You can just keep track of whether or not you are in the middle of an update. If you have multiple textviews, you could make a dictionary for the isCompleting variables.

- (void) controlTextDidChange: (NSNotification *)note {
    NSTextView * fieldEditor = [[note userInfo] objectForKey:@"NSFieldEditor"];

    if (!isCompleting) {
        isCompleting = YES;
        [fieldEditor complete:nil];
        isCompleting = NO;
    }
}


When your text field delegate gets controlTextDidChange:, you can call complete: on the Field Editor. This is the method that gets called when you press ESC or F5.

- (void) controlTextDidChange: (NSNotification *)note {
    NSTextView * fieldEditor = [[note userInfo] objectForKey:@"NSFieldEditor"];

    [fieldEditor complete:nil];
}

The tricky part is that when the completion menu is being navigated, it will cause controlTextDidChange: messages to be sent again, (although without changing the actual string) which will create an infinite loop. You will need some kind of flag to stop complete: from being called when you are already in the middle of a completion. For example, you can keep track of the last change the user made to the string and compare it with the current value of the field editor; if there's no user-initiated change, don't cause completion:

BOOL textDidNotChange = [lastTypedString isEqualToString:[fieldEditor string]];

if( textDidNotChange ){
    return;
}
else {
    lastTypedString = [[fieldEditor string] copy];
    [fieldEditor complete];
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜