NSTextView не показывает красные подчеркивания с орфографическими ошибками на слое

Когда NSTextView является подвидом NSView , поддерживаемым слоями ( -wantsLayer == YES ), он не отображает волнистые красные подчеркивания для слов с ошибками. Все, что нужно для воспроизведения этого, - это создать пустой проект Какао, открыть перо, перетащить NSTextView в окно и переключить представление содержимого окна, чтобы получить слой. Стрела - больше нет красных подчеркиваний.

Я немного поискал, и, похоже, это известная ситуация, которая сохраняется с 10.5. Однако я не могу найти обходного пути. Нет ли способа получить подчеркивание для рендеринга, когда NSTextView находится в представлении с поддержкой слоев?

Я могу представить себе переопределение NSTextView drawRect: и используя диспетчер компоновки, чтобы найти нужные прямоугольники с правильным набором временных атрибутов, которые указывают на орфографические ошибки, а затем сам рисовал красные волнистые линии, но это, конечно, полный взлом. Я также могу представить, как Apple исправит это в 10.7 (возможно), и вдруг в моем приложении появятся двойные подчеркивания или что-то в этом роде.


[обновить] Мое обходное решение

Мое текущее обходное решение было основано на упомянутом nptacek методе делегата проверки орфографии, который побудил меня глубже изучить путь, который я не замечал раньше, поэтому я собираюсь принять этот ответ, но опубликую что я сделал для потомков и / или для дальнейшего обсуждения.

Я использую 10.6.5. У меня есть подкласс NSTextView, который является представлением документа пользовательского подкласса NSClipView, который, в свою очередь, является подвидом моего окна contentView, в котором включены слои. Играя с этим, я в конце концов закомментировал все настройки, но проверка орфографии работала некорректно.

Я выделил, как мне кажется, две отдельные проблемы:

# 1 то, что NSTextView, когда размещенный в режиме просмотра с поддержкой слоев, даже не пытается нарисовать подчеркивание с орфографической ошибкой. Я проверил это, реализовав некоторые методы делегата проверки орфографии и наблюдая, как 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, но оно вроде близко и выполняет свою работу на данный момент. Надеюсь, это будет полезно для кого-то еще или, что еще лучше, кто-то придет сюда и скажет мне, что мне не хватает чего-то невероятно простого, и объяснит, как это исправить. :)

6
задан Sean 8 December 2010 в 16:37
поделиться