Когда NSTextView
является подпредставлением NSView
с подложкой (-wantsLayer == YES
), оно не отображает волнистые красные подчеркивания для слов с ошибками. Чтобы воспроизвести это, достаточно создать пустой проект Cocoa, открыть перо, перетащить NSTextView
в окно и переключить вид содержимого окна, чтобы получить слой. Бум - больше нет красных подчеркиваний.
Я провел некоторый поиск, и это, кажется, известная ситуация, которая была верна с 10.5. Однако я не могу найти обходной путь для этого. Нет ли способа получить подчеркивания для рендеринга, когда NSTextView
находится в представлении со слоем?
Я могу представить себе переопределение NSTextView
drawRect:
и использование диспетчера раскладки, чтобы найти правильные риты с соответствующим набором временных атрибутов, которые указывают на орфографические ошибки, а затем рисовать красные загогулины самостоятельно, но это, конечно, полный взлом. Я также могу представить, что Apple исправит это в 10.7 (возможно), и вдруг мое приложение будет иметь двойное подчеркивание или что-то в этом роде.
[обновление] Мой обходной путь
Мой текущий обходной путь был вдохновлен упомянутым методом делегирования проверки орфографии nptacek, который побудил меня копать глубже по пути, который я раньше не замечал, поэтому я приму этот ответ, но опубликую то, что я сделал для потомков и / или дальнейшего обсуждения.
Я бегу 10.6.5. У меня есть подкласс NSTextView, который является представлением документа пользовательского подкласса NSClipView, который, в свою очередь, является подвидом contentView моего окна, в котором включены слои. Играя с этим, я в конце концов закомментировал все настройки, и все же проверка орфографии работала неправильно.
Я выделил, что, как мне кажется, две разные проблемы:
# 1 заключается в том, что NSTextView, если он размещен в представлении со слоем, даже не удосуживается нарисовать подчеркивание с ошибками. (Я понял, основываясь на поиске в Google, что в 10,5 днях, когда он рисовал подчеркивания, могло быть время, но не в том месте, поэтому Apple, возможно, просто отключила их полностью, чтобы избежать этой проблемы в 10.6. Я не уверен, Может также быть некоторый побочный эффект от того, как я позиционирую вещи и т. Д., Которые заставили их вообще не появляться в моем случае. В настоящее время неизвестно.)
# 2 заключается в том, что когда NSTextView находится в этой ситуации, связанной со слоем, он, кажется, неправильно помечает текст как орфографическую ошибку, когда вы печатаете его, даже когда -isContinuousSpellCheckingEnabled установлен в YES. Я проверил это, реализовав некоторые методы делегирования для проверки орфографии и наблюдая, как NSTextView отправлял сообщения об изменениях, но никогда не уведомлял о том, чтобы установить текстовые диапазоны с ошибками - даже с явно ошибочными словами, которые будут показывать красное подчеркивание в TextEdit (и других текстовых представлениях в других приложениях). Я также переопределил NSTextView -handleTextCheckingResults: forRange: types: options: orthography: wordCount: чтобы увидеть то, что он видел, и он увидел то же самое там. Как будто NSTextView активно устанавливал слово под курсором как не написанное с ошибкой, а затем, когда пользователь вводит пробел или удаляется от него или чего-либо еще, он не перепроверял ошибки. Хотя я не совсем уверен.
Хорошо, чтобы обойти # 1 , я переопределил -drawRect: в моем собственном подклассе NSTextView, чтобы он выглядел так:
- (void)drawRect:(NSRect)rect
{
[super drawRect:rect];
[self drawFakeSpellingUnderlinesInRect:rect];
}
Затем я реализовал -drawFakeSpellingUnderlinesInRect: чтобы использовать layoutManager для получения текстовых диапазонов, которые содержат NSSpellingStateAttributeName, в качестве временного атрибута, и отображать точечный шаблон, достаточно близкий к стандартному образцу точных ошибок ввода OSX.
- (void)drawFakeSpellingUnderlinesInRect:(NSRect)rect
{
CGFloat lineDash[2] = {0.75, 3.25};
NSBezierPath *underlinePath = [NSBezierPath bezierPath];
[underlinePath setLineDash:lineDash count:2 phase:0];
[underlinePath setLineWidth:2];
[underlinePath setLineCapStyle:NSRoundLineCapStyle];
NSLayoutManager *layout = [self layoutManager];
NSRange checkRange = NSMakeRange(0,[[self string] length]);
while (checkRange.length > 0) {
NSRange effectiveRange = NSMakeRange(checkRange.location,0);
id spellingValue = [layout temporaryAttribute:NSSpellingStateAttributeName atCharacterIndex:checkRange.location longestEffectiveRange:&effectiveRange inRange:checkRange];
if (spellingValue) {
const NSInteger spellingFlag = [spellingValue intValue];
if ((spellingFlag & NSSpellingStateSpellingFlag) == NSSpellingStateSpellingFlag) {
NSUInteger count = 0;
const NSRectArray rects = [layout rectArrayForCharacterRange:effectiveRange withinSelectedCharacterRange:NSMakeRange(NSNotFound,0) inTextContainer:[self textContainer] rectCount:&count];
for (NSUInteger i=0; i<count; i++) {
if (NSIntersectsRect(rects[i], rect)) {
[underlinePath moveToPoint:NSMakePoint(rects[i].origin.x, rects[i].origin.y+rects[i].size.height-1.5)];
[underlinePath relativeLineToPoint:NSMakePoint(rects[i].size.width,0)];
}
}
}
}
checkRange.location = NSMaxRange(effectiveRange);
checkRange.length = [[self string] length] - checkRange.location;
}
[[NSColor redColor] setStroke];
[underlinePath stroke];
}
Таким образом, после этого я вижу красные подчеркивания, но, похоже, это не обновляет состояние правописания при вводе. Чтобы обойти эту проблему, я реализовал в своем подклассе NSTextView следующие злые хаки:
- (void)setNeedsFakeSpellCheck
{
if ([self isContinuousSpellCheckingEnabled]) {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(forcedSpellCheck) object:nil];
[self performSelector:@selector(forcedSpellCheck) withObject:nil afterDelay:0.5];
}
}
- (void)didChangeText
{
[super didChangeText];
[self setNeedsFakeSpellCheck];
}
- (void)updateInsertionPointStateAndRestartTimer:(BOOL)flag
{
[super updateInsertionPointStateAndRestartTimer:flag];
[self setNeedsFakeSpellCheck];
}
- (void)forcedSpellCheck
{
[self checkTextInRange:NSMakeRange(0,[[self string] length]) types:[self enabledTextCheckingTypes] options:nil];
}
Он не работает так же, как реальное, ожидаемое поведение OSX, но он довольно близок, и на данный момент он выполняет свою работу. Надеюсь, это будет полезно для кого-то еще, или, что еще лучше, кто-то приходит сюда и говорит мне, что я упустил что-то невероятно простое, и объясняет, как это исправить. :)