问题
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