问题
I'd like to do a "find" operation in an NSTextView
without using the built-in find bar. How can I programmatically set a search string and have the results highlighted inside the text view?
This is for macOS 10.12 and higher.
FWIW, this is not a duplicate of this question: NSTextFinder set search string and clear visual feedback programatically
That question is about programmatically controlling the find bar UI, either clearing previous find results or populating the find bar search field.
This question is about invoking a "find" operation programmatically without using the find bar UI at all.
回答1:
Here's my test code (hacky, experimental):
@interface ViewController ()
@property (strong) NSTextFinder *textFinder;
@property (weak) IBOutlet NSTextView *textView; // find Uses Bar, Incremental Searching is on
@property (weak) NSView *myFindBarView;
@property (weak) IBOutlet NSView *findBarContainerView; // hidden
@property BOOL barVisible;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.textFinder = [[NSTextFinder alloc] init];
self.textFinder.incrementalSearchingEnabled = YES;
self.textFinder.incrementalSearchingShouldDimContentView = YES;
self.textFinder.client = (id<NSTextFinderClient>)self.textView;
self.textFinder.findBarContainer = self;
[self.textFinder performAction:NSTextFinderActionShowFindInterface];
}
- (IBAction)testSearchString:(id)sender {
// action method of a Test button, searches for "found"
[self.textFinder cancelFindIndicator];
// search the subviews for a view of class NSSearchField
__block __weak NSSearchField *(^weak_findSearchField)(NSView *);
NSSearchField *(^findSearchField)(NSView *);
weak_findSearchField = findSearchField = ^(NSView *view) {
if ([view isKindOfClass:[NSSearchField class]])
return (NSSearchField *)view;
__block NSSearchField *foundView = nil;
[view.subviews enumerateObjectsUsingBlock:^(NSView *subview, NSUInteger idx, BOOL *stop) {
foundView = weak_findSearchField(subview);
if (foundView)
*stop = YES;
}];
return foundView;
};
NSSearchField *searchField = findSearchField(self.myFindBarView);
[searchField setStringValue:@"found"];
// execute the action of the search field to confirm the new value and do a search
[searchField sendAction:searchField.action to:searchField.target];
/* add to select all
[self.textFinder performAction:NSTextFinderActionSelectAll];
*/
}
// NSTextFinderBarContainer
- (void)findBarViewDidChangeHeight {
}
- (NSView *)findBarView {
return self.myFindBarView;
}
- (void)setFindBarView:(NSView *)theView {
self.myFindBarView = theView;
if (theView) {
NSRect frame = theView.frame;
frame.size.width = self.findBarContainerView.bounds.size.width;
theView.frame = frame;
[self.findBarContainerView addSubview:theView];
}
}
- (NSView *)contentView {
return self.textView.enclosingScrollView.contentView;
}
- (BOOL)isFindBarVisible {
return self.barVisible;
}
- (void)setFindBarVisible:(BOOL)theVisible {
self.barVisible = theVisible;
}
@end
来源:https://stackoverflow.com/questions/46817490/how-to-use-nstextfinder-programmatically