Многостраничные документы

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

Протокол печати

Чтобы распечатать документ с несколькими страницами, платформа и представление взаимодействуют следующим образом. Сначала платформа отображает диалоговое окно "Печать", создает контекст устройства для принтера и вызывает функцию члена StartDoc объекта CDC. Затем для каждой страницы документа платформа вызывает функцию CDC члена StartPage объекта, предписывает объекту представления распечатать страницу и вызывает функцию члена EndPage. Если перед запуском определенной страницы необходимо изменить режим принтера, представление вызывает ResetDC, который обновляет структуру DEVMODE , содержащую сведения о новом режиме принтера. После печати всего документа платформа вызывает функцию-член EndDoc .

Переопределение функций классов представления

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

Переопределимые функции CView для печати

Имя Причина переопределения
OnPreparePrinting Вставка значений в диалоговом окне "Печать", особенно длина документа
OnBeginPrinting Выделение шрифтов или других ресурсов GDI
Onpreparedc Настройка атрибутов контекста устройства для заданной страницы или разбиение на страницы во время печати
Onprint Печать заданной страницы
OnEndPrinting Удаление ресурсов GDI

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

На следующем рисунке показаны шаги, связанные с процессом печати, и показано, где вызываются функции-члены печати.CView Остальная часть этой статьи подробно описывает большинство этих шагов. Дополнительные части процесса печати описаны в статье о выделении ресурсов GDI.

Printing loop process.
Цикл печати

Разбиение на страницы

Платформа хранит большую часть информации о задании печати в структуре CPrintInfo . Некоторые из значений, CPrintInfo относящихся к разбиению на страницы. Эти значения доступны, как показано в следующей таблице.

Сведения о номере страницы, хранящиеся в CPrintInfo

Переменная члена или

Имена функций
Номер страницы, на который ссылается
GetMinPage/SetMinPage Первая страница документа
GetMaxPage/SetMaxPage Последняя страница документа
GetFromPage Первая страница для печати
GetToPage Последняя страница для печати
m_nCurPage Страница, в настоящее время печатаемая

Номера страниц начинаются с 1, то есть первая страница нумеруется 1, а не 0. Дополнительные сведения об этих и других членах CPrintInfo см. в справочнике по MFC.

В начале процесса печати платформа вызывает функцию-член представления OnPreparePrinting , передав указатель на CPrintInfo структуру. Мастер приложений предоставляет реализацию OnPreparePrinting , которая вызывает DoPreparePrinting, еще одну функцию-член CView. DoPreparePrinting — это функция, отображающая диалоговое окно "Печать" и создающая контекст устройства принтера.

На этом этапе приложение не знает, сколько страниц находятся в документе. Он использует значения по умолчанию 1 и 0xFFFF для чисел первой и последней страницы документа. Если вы знаете, сколько страниц документа имеется, переопределите OnPreparePrinting и вызовите [SetMaxPage]-reference/cprintinfo-class.md#setmaxpage) для структуры перед отправкой в нее CPrintInfoDoPreparePrinting. Это позволяет указать длину документа.

DoPreparePrinting Затем отображается диалоговое окно "Печать". При возвращении структура содержит значения, CPrintInfo указанные пользователем. Если пользователь хочет распечатать только выбранный диапазон страниц, он или она может указать начальные и конечные номера страниц в диалоговом окне "Печать". Платформа извлекает эти значения с помощью GetFromPage функций GetToPageCPrintInfo. Если пользователь не указывает диапазон страниц, платформа вызывает GetMinPage и GetMaxPage использует значения, возвращаемые для печати всего документа.

Для каждой страницы документа, которую нужно распечатать, платформа вызывает две функции-члены в классе представления OnPrepareDC и OnPrint и передает каждую функцию двумя параметрами: указатель на объект CDC и указатель на CPrintInfo структуру. Каждый раз, когда платформа вызывает OnPrepareDC и OnPrintпередает другое значение в элементе CPrintInfo m_nCurPage структуры. Таким образом платформа сообщает представлению, какую страницу следует распечатать.

Функция-член OnPrepareDC также используется для отображения экрана. Он вносит корректировки в контекст устройства перед выполнением рисования. OnPrepareDC служит аналогичной ролью в печати, но есть несколько различий: во-первых, CDC объект представляет контекст устройства принтера вместо контекста устройства экрана, а второй объект CPrintInfo передается в качестве второго параметра. (Этот параметр имеет значение Значение NULL при OnPrepareDC вызове экрана.) Переопределите OnPrepareDC , чтобы внести изменения в контекст устройства, на основе которого печатается страница. Например, можно переместить источник окна просмотра и область вырезки, чтобы убедиться, что соответствующая часть документа будет напечатана.

Функция-член OnPrint выполняет фактическую печать страницы. В статье "Как выполняется печать по умолчанию" показано, как платформа вызывает OnDraw с контекстом устройства принтера для выполнения печати. Точнее, платформа вызывает OnPrint структуру CPrintInfo и контекст устройства и OnPrint передает контекст OnDrawустройства в . Переопределите OnPrint для выполнения любой отрисовки, которая должна выполняться только во время печати, а не для отображения экрана. Например, чтобы распечатать верхние или нижние колонтитулы (дополнительные сведения см. в статье "Верхние и нижние колонтитулы "). Затем вызовите OnDraw из переопределения OnPrint , чтобы сделать отрисовку обычной для экрана и печати.

Тот факт, что OnDraw выполняет отрисовку для отображения экрана и печати, означает, что ваше приложение — WYSIWYG: "Что вы видите, это то, что вы получаете". Однако предположим, что вы не пишете приложение WYSIWYG. Например, рассмотрим текстовый редактор, использующий полужирный шрифт для печати, но отображает коды элементов управления для указания полужирного текста на экране. В такой ситуации вы используете OnDraw строго для отображения экрана. При переопределении OnPrintзамените вызов OnDraw вызовом отдельной функции рисования. Эта функция рисует документ так, как он отображается на бумаге, используя атрибуты, которые не отображаются на экране.

Страницы принтера и страницы документов

Если вы ссылаетесь на номера страниц, иногда необходимо различать концепцию принтера страницы и концепцию документа. С точки зрения принтера страница является одним листом бумаги. Однако один лист бумаги не обязательно равен одной странице документа. Например, если вы печатаете бюллетень, где должны быть сложены листы, один лист бумаги может содержать как первые, так и последние страницы документа рядом. Аналогичным образом, если вы печатаете электронную таблицу, документ не состоит из страниц вообще. Вместо этого один лист бумаги может содержать строки 1–20, столбцы 6–10.

Все номера страниц в структуре CPrintInfo ссылаются на страницы принтера. Платформа вызывается OnPrepareDC и OnPrint один раз для каждого листа бумаги, который будет проходить через принтер. При переопределении функции OnPreparePrinting для указания длины документа необходимо использовать страницы принтера. Если есть одно-одно соответствие (т. е. одна страница принтера равна одной странице документа), то это легко. Если, с другой стороны, страницы документов и страницы принтера не соответствуют напрямую, необходимо перевести между ними. Например, рекомендуется печатать электронную таблицу. При переопределении OnPreparePrintingнеобходимо вычислить, сколько листов бумаги потребуется для печати всей электронной таблицы, а затем использовать это значение при вызове SetMaxPage функции-члена CPrintInfo. Аналогичным образом при переопределении OnPrepareDCнеобходимо преобразовать m_nCurPage в диапазон строк и столбцов, которые будут отображаться на этом конкретном листе, а затем соответствующим образом настроить источник окна просмотра.

Разбиение на страницы во время печати

В некоторых ситуациях класс представления может заранее не знать, как долго документ находится до его печати. Например, предположим, что приложение не является WYSIWYG, поэтому длина документа на экране не соответствует его длине при печати.

Это приводит к SetMaxPage проблеме при переопределении OnPreparePrinting для класса представления: невозможно передать значение в функцию структуры CPrintInfo, так как длину документа не известно. Если пользователь не указывает номер страницы для остановки с помощью диалогового окна "Печать", платформа не знает, когда остановить цикл печати. Единственный способ определить, когда остановить цикл печати заключается в том, чтобы распечатать документ и увидеть, когда он заканчивается. Класс представления должен проверка для конца документа во время его печати, а затем сообщить платформе о достижении конца.

Платформа использует функцию OnPrepareDC класса представления, чтобы сообщить ему, когда нужно остановиться. После каждого вызова OnPrepareDCплатформы проверка член CPrintInfo структуры с именем m_bContinuePrinting. Значение по умолчанию — TRUE. Пока она остается такой, платформа продолжает цикл печати. Если задано значение FALSE, платформа останавливается. Чтобы выполнить разбиение на страницы во время печати, переопределите OnPrepareDC значение проверка, достигнуто ли конец документа, и задайте для него значение false m_bContinuePrintingзначение FALSE.

Реализация по умолчанию наборов OnPrepareDCm_bContinuePrintingзначение FALSE , если текущая страница больше 1. Это означает, что если длина документа не указана, платформа предполагает, что документ имеет длину одной страницы. Одним из последствий этого является то, что при вызове версии OnPrepareDCбазового класса необходимо быть осторожным. Не предполагайте, что m_bContinuePrinting будет TRUE после вызова версии базового класса.

Что вы хотите узнать больше о

См. также

Печать
Класс CView
Класс CDC