Задачи набора PDF

Эта глава показывает, как можно реализовать общие задачи с Набором PDF.

Реализация PDFView

Большинство разработчиков просто захочет вывести на экран информацию о PDF в своих представлениях, таким образом, PDFView будет отвечать всем требованиям приятно.

Элемент пользовательского интерфейса PDFView доступен в Интерфейсном Разработчике, таким образом, необходимо использовать это везде, где Вы хотите, чтобы Ваше приложение вывело на экран содержание PDF. Обратите внимание на то, что необходимо установить палитру PDF Kit в /Developer/Extras/Palettes/PDFKit.palette сделать PDFViews доступный.

Для добавления палитры PDFKit в Интерфейсном Разработчике выберите вкладку Palettes в панели Preferences. Нажмите Add … кнопка, перейдите к /Developer/Extras/Palettes папка и выбор палитра PDFKit. Затем, выберите пункт меню Customize Toolbar в меню Tools/Palettes и перетащите палитру PDFKit на панель инструментов для создания его видимым.

После добавления элемента PDFView в Вашем файле пера можно добавить содержание PDF из приложения путем вызова метода PDFDocument initWithURL. Например, Вы могли использовать код как следующее:

PDFDocument *pdfDoc;
 
pdfDoc = [[PDFDocument alloc] initWithURL: [NSURL fileURLWithPath: [self fileName]]];
[_pdfView setDocument: pdfDoc];

Также, если Ваши данные PDF хранятся в другой форме, можно использовать метод PDFDocument initWithData:. Пользователи могут также перетащить документы в представление.

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

Набор PDF в предварительном просмотре

Предварительный просмотр в OS X v10.4 использует Набор PDF, таким образом, можно использовать это приложение в качестве руководства для наблюдения то, что возможно в собственных представлениях PDF. Много вызовов метода в Наборе PDF имеют сопоставимый пункт меню в Предварительном просмотре. Таблица 2-1 показывает корреспонденцию между различными пунктами меню и их эквивалентами API.

Табличные 2-1  Пункты меню Предварительного просмотра по сравнению с методами Набора PDF

Меню

Подменю

Метод

Представление

Дисплей PDF

PDFView: - setDisplayMode: и - setDisplayBox:

Увеличение

PDFView: - zoomIn:

Уменьшение

PDFView: - zoomOut:

Пойти

Затем

PDFView: - goToNextPage:

Предыдущий

PDFView: - goToPreviousPage:

Перейдите к странице

PDFView: - goToPage:

Сначала

PDFView: - goToFirstPage:

В последний раз

PDFView: - goToLastPage:

Назад

PDFView: - goBack:

Передать

PDFView: - goForward:

Инструменты

Вращайтесь оставленный

PDFPage: - setRotation: к - rotation - 90

Поверните право

PDFPage: - setRotation: к - rotation +90

Аннотация

initWithBounds:для надлежащего подкласса аннотации (такого как PDFAnnotationCircle)

Создание основ

Много документов в формате PDF содержат основы, таким образом, Ваше приложение будет обычно хотеть вывести на экран эту информацию также.

Обратите внимание на то, что, потому что некоторые документы в формате PDF не содержат информацию о схеме, необходимо, вероятно, сделать контурное отображение дополнительным элементом в пользовательском интерфейсе. Например, можно вывести на экран основы в секции, которая может быть закрыта если не необходимый.

Можно использовать класс NSOutlineView для отображения основ PDF. Экземпляры этого класса автоматически выводят на экран иерархию схемы с треугольниками раскрытия и активными ссылками с надлежащими страницами PDF. Перечисление 2-1 показывает, как Вы могли бы сделать так.

Перечисление 2-1  , Загружающее PDF, обрисовывает в общих чертах информацию

_outline = [[_pdfView document] outlineRoot];// 1
    if (_outline)
    {
        [_noOutlineText removeFromSuperview];// 2
        _noOutlineText = NULL;
 
        [_outlineView reloadData];// 3
    }
    else
    {
        [[_outlineView enclosingScrollView] removeFromSuperview];// 4
        _outlineView = NULL;
    }

Вот то, как работает код:

  1. Получает корневой (самый верхний) элемент схемы. _outline экземпляр PDFOutline.

  2. Если корневая схема существует, удаляет текст заполнителя, указывающий “Схему”.

  3. Загрузки PDF обрисовывают в общих чертах информацию в представление схемы. Представление схемы вызывает Ваши методы делегата определить элементы в иерархии схемы.

  4. Если корневая схема не существует, удаляет представление схемы, оставляя позади текст заполнителя.

После вызова reloadData метод, представление схемы вызывает различные методы делегата источника данных заполнить схему. Эти методы делегата определяются в протоколе NSOutlineViewDataSource. Ваше приложение должно реализовать эти методы так, чтобы надлежащие данные PDF были добавлены к схеме.

Перечисление 2-2 показывает метод делегата для получения числа дочерних элементов, просто возвращающего значение, полученное методом PDFOutline numberOfChildren. Если параметр элемента NULL, этот метод возвращает число дочерних элементов для корневой схемы.

  Метод делегата перечисления 2-2 для определения числа дочерних элементов

- (int) outlineView: (NSOutlineView *) outlineView numberOfChildrenOfItem: (id) item
{
    if (item == NULL)
    {
        if (_outline)
            return [_outline numberOfChildren];
        else
            return 0;
    }
    else
        return [(PDFOutline *)item numberOfChildren];
}

Перечисление 2-3 показывает метод делегата для получения определенной дочерней схемы путем вызова метода PDFOutline childAtIndex. Если параметр элемента NULL, этот метод возвращает соответствующий дочерний элемент корневой схемы.

  Метод делегата перечисления 2-3 для получения дочернего элемента

- (id) outlineView: (NSOutlineView *) outlineView child: (int) index ofItem: (id) item
{
    if (item == NULL)
    {
        if (_outline)
            return [_outline childAtIndex: index];
        else
            return NULL;
    }
    else
        return [(PDFOutline *)item childAtIndex: index];

Перечисление 2-4 показывает метод делегата для определения, если элемент схемы расширяем (т.е. имеет ли это дочерние основы).

  Метод делегата перечисления 2-4 для определения, если элемент имеет дочерние элементы

- (BOOL) outlineView: (NSOutlineView *) outlineView isItemExpandable: (id) item
{
    if (item == NULL)
    {
        if (_outline)
            return ([_outline numberOfChildren] > 0);
        else
            return NO;
    }
    else
        return ([(PDFOutline *)item numberOfChildren] > 0);
}

Перечисление 2-5 показывает метод делегата для получения метки элемента схемы, вызывающей метод PDFOutline label. Метка является просто строкой, выведенной на экран в представлении схемы (например, заголовок главы).

  Метод делегата перечисления 2-5 для получения содержания элемента

- (id) outlineView: (NSOutlineView *) outlineView
        objectValueForTableColumn: (NSTableColumn *) tableColumn
        byItem: (id) item
{
    return [(PDFOutline *)item label];
}

Когда пользователь выбирает элемент схемы, Ваше приложение должно обновить дисплей PDF для показа страницы, соответствующей тому элементу. Самый простой способ сделать так состоит в том, чтобы вызвать PDFView’s goToDestination метод, как показано в Перечислении 2-6.

Перечисление 2-6  , Выводящее на экран страницу, связалось с элементом схемы

- (IBAction) takeDestinationFromOutline: (id) sender
{
    [_pdfView goToDestination: [[sender itemAtRow:
                                [sender selectedRow]] destination]];
}

Кроме того, если пользователь прокручивает или иначе перемещается через документ, Ваше приложение должно обновить схему для выделения элемента схемы, соответствующего в настоящее время выводимой на экран странице. Можно сделать так путем установки обработчика уведомления, который вызовут каждый раз изменениями страницы (т.е. когда PDFViewPageChangedNotification отправляется). Перечисление 2-7, как то, как Вы могли бы сделать так.

Перечисление 2-7  , Обновляющее схему, когда изменяется страница

- (void) pageChanged: (NSNotification *) notification
{
    unsigned int    newPageIndex;
    int             numRows;
    int             i;
    int             newlySelectedRow;
 
    if ([[_pdfView document] outlineRoot] == NULL)// 1
        return;
 
    newPageIndex = [[_pdfView document] indexForPage: // 2
                                            [_pdfView currentPage]];
 
    // Walk outline view looking for best firstpage number match.
    newlySelectedRow = -1;
    numRows = [_outlineView numberOfRows];
    for (i = 0; i < numRows; i++)// 3
    {
        PDFOutline  *outlineItem;
 
        // Get the destination of the given row....
        outlineItem = (PDFOutline *)[_outlineView itemAtRow: i];
 
        if ([[_pdfView document] indexForPage:
                    [[outlineItem destination] page]] == newPageIndex)
        {
            newlySelectedRow = i;
            [_outlineView selectRow: newlySelectedRow
                                        byExtendingSelection: NO];
            break;
        }
        else if ([[_pdfView document] indexForPage:
                    [[outlineItem destination] page]] > newPageIndex)
        {
            newlySelectedRow = i - 1;
            [_outlineView selectRow: newlySelectedRow
                                        byExtendingSelection: NO];
            break;
        }
    }
 
    if (newlySelectedRow != -1)// 4
        [_outlineView scrollRowToVisible: newlySelectedRow];
}

Вот то, как работает код:

  1. Проверки, чтобы видеть, существует ли корневая схема. В противном случае тогда нет никакой схемы для обновления, таким образом, просто возвращаются.

  2. Получает индексное значение для текущей страницы. Метод PDFView currentPage возвращает объект PDFPage и метод PDFDocument indexForPage возвращает фактический индекс для той страницы. Это индексное значение основано на нуле, таким образом, оно не обязательно соответствует номеру страницы.

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

    • Индекс элемента схемы соответствует индекс новой страницы. Если так, выделите этот элемент (использующий метод NSTableView selectRow:byExtendingSelection).

    • Индекс элемента схемы больше, чем индекс страницы. Если так, соответствие не было возможно, поскольку индекс соответствует скрытому дочернему элементу видимого элемента. В этом случае использовать selectRow выделить родительский элемент схемы (текущая строка-1).

  4. Вызовите метод NSTableView scrollRowToVisible скорректировать представление схемы (если необходимый) для создания выделенного элемента видимым.

Поиск документа в формате PDF

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

Для простой строки поиском строки Ваше приложение может просто вызвать метод PDFDocument findString:fromSelection:withOptions:.

- (PDFSelection *) findString:(NSString *)string
         fromSelection:PDFSelection *selection:withOptions:(int)options

Вывести на экран выбор возвратилось, можно вызвать метод PDFView setCurrentSelection, который выделяет выбор, сопровождаемый scrollSelectionToVisible.

Можно указать следующие опции:

Путем передачи NULL для выбора можно начать поиск с начала (или конец) документа. Путем передачи нового соответствия для выбора можно реализовать, “Находят Снова” поведение. Если findString вызовите возвраты NULL, это означает, что или строка не была найдена, или поиск достиг конца (или начинающийся) документа.

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

Если Вы не уверены, что поиск будет краток, необходимо принять решение использовать beginFindString:withOptions:

Поскольку это - асинхронный поиск, PDFDocument включает две других полезных находки связанные методы:

Перечисление 2-8 показывает, как Вы могли бы инициировать поиск:

Перечисление 2-8  , Начинающее асинхронный поиск

- (void) doFind: (id) sender
{
    if ([[_pdfView document] isFinding])// 1
        [[_pdfView document] cancelFindString];
 
    if (_searchResults == NULL)// 2
        _searchResults = [NSMutableArray arrayWithCapacity: 10];
 
    [[_pdfView document] beginFindString: [sender stringValue] // 3
                withOptions: NSCaseInsensitiveSearch];
}

Вот то, как работает код:

  1. Отмены любые текущие поиски.

  2. Выделяет непостоянный массив для содержания результатов поиска, если Вы уже не существуете.

  3. Вызывает метод PDFDocument beginFindString:withOptions: с желаемой строкой поиска.

Во время поиска Набор PDF отсылает уведомления, на которые может реагировать Ваше приложение:

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

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

Уведомление соответствия находки отправляется каждый раз, когда соответствие найдено для строки поиска. Обычно Вы захотите получить строковый выбор и сохранить его в массиве для более позднего дисплея. Однако в большинстве случаев может быть проще использовать метод делегата PDFDocument didMatchString, который автоматически передает Вас соответствующий выбор. Перечисление 2-9 показывает, как Вы могли бы реализовать делегата, чтобы взять каждую соответствующую строку и добавить его к массиву результатов поиска в NSTableView.

Перечисление 2-9  , Добавляющее результаты поиска к табличному представлению

- (void) didMatchString: (PDFSelection *) instance
{
    // Add page label to our array.
    [_searchResults addObject: [instance copy]];
 
    // Force a reload.
    [_searchTable reloadData];
}

Здесь _searchResults экземпляр NSMutableArray, и _searchTable экземпляр NSTableView.

Чтобы удостовериться, что NSTableView выводит на экран результаты поиска правильно, необходимо реализовать методы источника данных делегата (подобный требуемым для NSOutlineView). Эти методы делегата определяются в протоколе NSTableDataSource.

Перечисление 2-10 показывает метод делегата для определения числа строк в табличном представлении. Этот метод просто получает число элементов в результатах поиска путем вызова метода NSMutableArray count.

Перечисление 2-10  , Определяющее число строк в таблице

- (int) numberOfRowsInTableView: (NSTableView *) aTableView
{
    return ([_searchResults count]);
}

Перечисление 2-11 показывает метод источника данных делегата для получения значения определенного столбца.

Перечисление 2-11  Получая значение для столбца

- (id) tableView: (NSTableView *) aTableView objectValueForTableColumn:
            (NSTableColumn *) theColumn
            row: (int) rowIndex
{
    if ([[theColumn identifier] isEqualToString: @"page"])
        return ([[[[_searchResults objectAtIndex: rowIndex] pages]
                     objectAtIndex: 0] label]);
    else if ([[theColumn identifier] isEqualToString: @"section"])
    {
        NSString    *label = [[[_pdfView document] outlineItemForSelection:
                         [_searchResults objectAtIndex: rowIndex]] label];
        return label;
    }
    else
        return NULL;
}

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

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

Рисунок 2-1  , Присваивающий идентификаторы столбцов в Интерфейсном Разработчике
Assigning column identifiers in Interface Builder

Для этого примера:

Когда пользователь выбирает элемент в результатах поиска, Ваше приложение должно вывести на экран соответствующую страницу. Перечисление 2-12 показывает, как Вы могли бы сделать настолько использующее уведомление NSTableView.

Перечисление 2-12  , Обрабатывающее выбор в таблице

- (void) tableViewSelectionDidChange: (NSNotification *) notification
{
    int rowIndex;
 
    // What was selected.  Skip out if the row has not changed.
    rowIndex = [(NSTableView *)[notification object] selectedRow];// 1
    if (rowIndex >= 0)
    {
        [_pdfView setCurrentSelection: // 2
                    [_searchResults objectAtIndex: rowIndex]];
        [_pdfView scrollSelectionToVisible: self];// 3
    }
}

Когда элемент выбран и вызывает Ваш метод делегата, табличное представление отправляет NSTableViewSelectionDidChangeNotification tableViewSelectionDidChange. Вот то, как работает код:

  1. Проверки, чтобы видеть, допустим ли выбор.

  2. Устанавливает текущий выбор в тот, по которому щелкнул пользователь.

  3. Обновляет представление PDF для показа страницы, содержащей выбор.

Для получения дополнительной информации о реализации этих методов делегата, см. Руководство по программированию Табличного представления для Mac в Документации Опыта Потребителя Какао.