Используя текстовые таблицы

Текстовая система Какао поддерживает текстовые таблицы в версии 10.4 OS X и позже. Основные включенные классы NSTextTable, который представляет таблицу, NSTextTableBlock, который представляет блок текста, появляющегося как ячейка в таблице и ее суперкласс, NSTextBlock. Эта статья объясняет, как добавить табличную поддержку Вашему приложению.

Добавление панели текстовой таблицы

NSTextView имеет встроенную поддержку текстовых таблиц, обеспечивающую самый простой способ добавить табличную поддержку Вашему текстовому представлению. Эта табличная поддержка находится в форме метода действия orderFrontTablePanel:. Этот метод вставляет таблицу в текстовое представление и открывает немодальное служебное окно, плавающее по окнам приложения. В то время как курсор или выбор находятся в таблице, эта табличная панель позволяет пользователю управлять атрибутами таблицы. Табличная панель показана в панели Текстовой таблицы.

  Панель Текстовой таблицы рисунка 1
Text table panel

Пользователь может изменить другие аспекты таблицы, такие как размер ячейки и содержание, непосредственным управлением с курсором.

Для предоставления доступа к панели текстовой таблицы доступной в текстовом представлении используйте Интерфейсного Разработчика для добавления orderFrontTablePanel: метод действия для Вашего первого респондента и подключения это к пункту меню, как показано в Соединении метода действия.

Рисунок 2  , Соединяющий метод действия
Connecting the action methodConnecting the action method

NSTextView определяет подобные методы действия для открытия списка, ссылки и панелей расстояния между абзацами.

Поддержка текстовых таблиц программно

Если Вы не хотите использовать панель текстовой таблицы, можно поддерживать таблицы программно при помощи NSTextTable и связанные классы непосредственно. Основной класс в этой группе NSTextBlock, который представляет блок текста, размеченного в подобласти текстового контейнера. При работе с таблицами Вы используете его подкласс, NSTextTableBlock, который представляет текстовый блок, появляющийся как ячейка в таблице. Сама таблица представлена отдельным классом, NSTextTable. Весь из NSTextTableBlock объекты, представляя ячейки в таблице, относятся к NSTextTable объект, управляющий их размером и расположением.

Текстовые блоки появляются как атрибуты в абзацах как часть стиля абзаца. NSParagraphStyle объект может иметь массив текстовых блоков, представляющих ячейки таблицы, содержащие абзац. Стиль абзаца использует массив, потому что ячейки таблицы могут быть вложены, и текстовые блоки упорядочиваются в массиве от наиболее удаленного до самого внутреннего. Например, если block1 содержит четыре абзаца, и средние два находятся также во внутреннем block2, то массив текстовых блоков для первых и четвертых абзацев (block1), который массив для вторых и третьих абзацев (block1, block2).

Вы добавляете текстовые блоки к объекту стиля абзаца использование NSMutableParagraphStyle метод setTextBlocks:, и NSParagraphStyle метод textBlocks возвращает массив.

Для реализации текстовой таблицы программно используйте следующую последовательность шагов:

  1. Создайте приписанную строку для таблицы.

  2. Создайте объект таблицы, определив номер столбцов.

  3. Создайте блок текстовой таблицы для первой ячейки строки, обратившись к объекту таблицы.

  4. Установите атрибуты для текстового блока.

  5. Создайте объект стиля абзаца для ячейки, установив текстовый блок как атрибут (вместе с любыми другими атрибутами абзацев, такими как выравнивание).

  6. Создайте приписанную строку для ячейки, добавив стиль абзаца как атрибут. Строка ячейки должна закончиться маркером абзаца, таким как символ новой строки.

  7. Добавьте строку ячейки к табличной строке.

  8. Повторите шаги 3-7 для каждой ячейки в таблице.

Методы показанный в таблице метод создания и метод создания Ячейки таблицы выполняют шаги от предыдущего списка. (Все методы в качестве примера в этой статье определяются в NSDocument подкласс основанного на документе приложения, но они могли так же легко принадлежать другому объекту, такому как текстовое представление.) Метод создания ячейки таблицы выполняет шаги 3-6 для каждой ячейки в таблице, с помощью толстых границ и контрастируя цвета в иллюстративных целях.

  Табличный метод создания перечисления 1

- (NSMutableAttributedString *) tableAttributedString
{
    // tableString is an ivar declared in the header file as NSMutableAttributedString *tableString;
    tableString = [[NSMutableAttributedString alloc] initWithString:@"\n\n"];
    NSTextTable *table = [[NSTextTable alloc] init];
    [table setNumberOfColumns:2];
 
    [tableString appendAttributedString:[self tableCellAttributedStringWithString:@"Cell1\n"
        table:table
        backgroundColor:[NSColor greenColor]
        borderColor:[NSColor magentaColor]
        row:0
        column:0]];
 
    [tableString appendAttributedString:[self tableCellAttributedStringWithString:@"Cell2\n"
        table:table
        backgroundColor:[NSColor yellowColor]
        borderColor:[NSColor blueColor]
        row:0
        column:1]];
 
    [tableString appendAttributedString:[self tableCellAttributedStringWithString:@"Cell3\n"
        table:table
        backgroundColor:[NSColor lightGrayColor]
        borderColor:[NSColor redColor]
        row:1
        column:0]];
 
    [tableString appendAttributedString:[self tableCellAttributedStringWithString:@"Cell4\n"
        table:table
        backgroundColor:[NSColor cyanColor]
        borderColor:[NSColor orangeColor]
        row:1
        column:1]];
 
    [table release];
    return [tableString autorelease];
}

  Метод создания Ячейки таблицы перечисления 2

- (NSMutableAttributedString *) tableCellAttributedStringWithString:(NSString *)string
        table:(NSTextTable *)table
        backgroundColor:(NSColor *)backgroundColor
        borderColor:(NSColor *)borderColor
        row:(int)row
        column:(int)column
{
    NSTextTableBlock *block = [[NSTextTableBlock alloc]
        initWithTable:table
        startingRow:row
        rowSpan:1
        startingColumn:column
        columnSpan:1];
    [block setBackgroundColor:backgroundColor];
    [block setBorderColor:borderColor];
    [block setWidth:4.0 type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder];
    [block setWidth:6.0 type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding];
 
    NSMutableParagraphStyle *paragraphStyle =
        [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    [paragraphStyle setTextBlocks:[NSArray arrayWithObjects:block, nil]];
    [block release];
 
    NSMutableAttributedString *cellString =
        [[NSMutableAttributedString alloc] initWithString:string];
    [cellString addAttribute:NSParagraphStyleAttributeName
        value:paragraphStyle
        range:NSMakeRange(0, [cellString length])];
    [paragraphStyle release];
 
    return [cellString autorelease];
}

Код в Табличном методе создания и методе создания Ячейки таблицы производит таблицу показанный в таблице вывод.

  Вывод Figure 3 Table
Table output

Для вставки таблицы в текст, выведенный на экран в текстовом представлении, реализуйте метод действия такой как один показанный в Перечислении 3. Этот метод вставляет табличную строку, созданную в Табличный метод создания в текстовом представлении, заменяя текущий выбор (или в точке вставки, если нет никакого выбора), и гарантирует, что отправляются надлежащие уведомления и сообщения делегата.

  Табличный метод действия вставки перечисления 3

- (void) insertMyTable:(id)sender
{
    NSRange charRange = [myTextView rangeForUserTextChange];
    NSTextStorage *myTextStorage = [myTextView textStorage];
 
    if ([myTextView isEditable] && charRange.location != NSNotFound)
        {
            NSMutableAttributedString *attrStringToInsert = [self tableAttributedString];
            if ([myTextView shouldChangeTextInRange:charRange replacementString:nil])
                {
                    [myTextStorage replaceCharactersInRange:charRange
                        withAttributedString:attrStringToInsert];
                    [myTextView setSelectedRange:NSMakeRange(charRange.location, 0)
                        affinity:NSSelectionAffinityUpstream stillSelecting:NO];
                    [myTextView didChangeText];
                }
        }
}

NSAttributedString имеет следующие удобные методы, которые можно использовать для определения диапазона в строке, покрытой текстовым блоком или таблицей:

rangeOfTextBlock:atIndex:

rangeOfTextTable:atIndex:

Если данное расположение не находится в указанном блоке или таблице, эти методы возвращают диапазон (NSNotFound, 0) .

Модель текстовой таблицы

Модель текстовой таблицы Какао получена прежде всего из табличной модели, определенной HTML и CSS, в котором таблицы накоплены от строк ячеек. Для описания модели таблицы CSS обратитесь к следующему URL:

http://www .w3.org/TR/CSS21/tables.html

Это сродство обеспечивает другой способ составить таблицы в тексте. Можно определить таблицу в HTML и использовать те данные для инициализации приписанной строки. Атрибуты той строки тогда определяют таблицу для рендеринга текстовой системой Какао. Можно использовать следующий NSAttributedString методы инициализации с этой целью:

initWithHTML:documentAttributes:

initWithHTML:options:documentAttributes:

initWithHTML:baseURL:documentAttributes:

initWithData:options:documentAttributes:error:

Управление появлением текстового блока

Позиция текстового блока определяется его текстовым контейнером или содержащий блок. В случае блока текстовой таблицы, представляющего ячейку в таблице, размером и позицией управляют текстовая таблица и отношение блока к другим блокам в таблице. Когда Вы инициализируете NSTextTableBlock объект, Вы указываете его строку и позицию столбцов как ячейка в его таблице, и Вы также указываете, охватывает ли это многократные строки или столбцы. NSTextTableBlock метод инициализации:

initWithTable:startingRow:rowSpan:startingColumn:columnSpan:

Метод создания ячейки таблицы показывает этот метод в использовании.

Кроме того, можно указать значение многих размерностей для каждого блока, или как абсолютное значение или как процент содержания блока. Эти размерности включают следующее:

Значение по умолчанию для каждой из этих размерностей 0 , указание никакого дополнения, границы, или поля, и естественной ширины и высоты. Естественная ширина и высота единственного текстового блока расширяются на ширину и высоту ее содержания блока (или текстовый контейнер); естественная ширина и высота многократных блоков делят пространство их содержания блока равномерно.

Следующие методы указывают или возвращаемые значения, связанные с этими размерностями:

setValue:type:forDimension:

valueForDimension:

valueTypeForDimension:

setWidth:type:forLayer:

setWidth:type:forLayer:edge:

widthForLayer:edge:

widthValueTypeForLayer:edge:

В этих методах тип значения относится к значениям процента или абсолютному. Размерность относится к минимуму, максимуму, и полной ширине и высоте блока. Уровень относится к дополнению, границе и полю. Эти параметры указаны константами, описанными в NSTextBlock

NSTextBlock обеспечивает следующие методы, чтобы указать и возвратить цвет фона и цвет рамки блока:

backgroundColor

setBackgroundColor:

borderColorForEdge:

setBorderColor:forEdge:

setBorderColor:

По умолчанию значения цвета nil , значение никакого цвета. Обратите внимание на то, что граница без цвета невидима.

Табличный процесс создания макета

Во время текстового расположения наборное устройство работает с NSTextBlock определить прямоугольники расположения для текстового блока. Если текстовый блок является экземпляром NSTextTableBlock, это вызывает свое содержание NSTextTable экземпляр для выполнения вычислений. Наборное устройство хранит результаты этих вычислений в его менеджере по расположению. Существуют методы в NSTextBlock, NSTextTable, и NSLayoutManager определенный для этого процесса создания макета, который можно использовать, если необходимо вмешаться в процесс.

Для начала процесса создания макета текстового блока наборное устройство предлагает большой прямоугольник, в котором должен соответствовать текстовый блок. Для наиболее удаленного блока это определяется текстовым контейнером; для внутренних блоков это определяется содержанием блока. Блочный объект тогда решает, какую область в предложенном прямоугольнике он должен фактически занять.

Текстовый блок фактически определяет два прямоугольника: во-первых, прямоугольник расположения, в котором должен быть размечен текст в блоке; во-вторых, прямоугольник границ, содержащий дополнительное пространство для дополнения, границ, декоративного обрамления и полей. Текстовый блок сразу вычисляет прямоугольник расположения, прежде чем наборное устройство разметит первый глиф, потому что это необходимо для всего последующего расположения текста в блоке. Прямоугольник расположения часто довольно высок, потому что в этой точке еще не была определена высота текста, который будет размечен. Текстовый блок сразу вычисляет прямоугольник границ после того, как последний глиф в блоке был размечен, и это основывается на фактическом прямоугольнике, используемом для текста в блоке. При некоторых обстоятельствах прямоугольник границ может быть скорректирован впоследствии, поскольку размечаются дополнительные блоки в той же таблице.

Для нахождения расположения и прямоугольников границ наборное устройство вызывает следующий NSTextBlock методы:

rectForLayoutAtPoint:inRect:textContainer:characterRange:

boundsRectForContentRect:inRect:textContainer:characterRange:

NSTextTableBlock объект, в свою очередь, вызовы NSTextTable объект выполнить эти вычисления, с помощью следующих методов:

rectForBlock:layoutAtPoint:inRect:textContainer:characterRange:

boundsRectForBlock:contentRect:inRect:textContainer:characterRange:

Наборное устройство хранит результаты этих методов в менеджере по расположению, использующем следующие методы:

setLayoutRect:forTextBlock:glyphRange:

setBoundsRect:forTextBlock:glyphRange:

Наборное устройство использует следующий NSLayoutManager методы, когда это должно определить пространство, использованное ранее положенными текстовыми блоками:

layoutRectForTextBlock:glyphRange:

layoutRectForTextBlock:atIndex:effectiveRange:

boundsRectForTextBlock:glyphRange:

boundsRectForTextBlock:atIndex:effectiveRange:

Предыдущие методы вызывают генерацию глифа, но не вызывают расположение. Когда методы вызывают во время расположения, это избегает бесконечной рекурсии. По той же причине, следующим вариантам существующих NSLayoutManager методы имеют опцию препятствовать тому, чтобы они вызвали расположение:

lineFragmentRectForGlyphAtIndex:effectiveRange:withoutAdditionalLayout:

lineFragmentUsedRectForGlyphAtIndex:effectiveRange:withoutAdditionalLayout:

textContainerForGlyphAtIndex:effectiveRange:withoutAdditionalLayout:

Если никакой прямоугольник не был установлен, предыдущий возврат методов NSZeroRect .

Во время дисплея текст составлен, как обычно, как описано в “менеджере по Расположению”, за исключением того, что текстовый блок рисует фоновое и декоративное обрамление, в то время как фоны глифа рисуются, с помощью следующего метода:

drawBackgroundWithFrame:inView:characterRange:layoutManager:

Если текстовый блок NSTextTableBlock объект, это вызывает свою текстовую таблицу с этой целью, с помощью следующего NSTextTable метод:

drawBackgroundForBlock:withFrame:inView:characterRange:layoutManager: