Поделиться через


Документы с несколькими страницами

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

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

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

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

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

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

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

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

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

Процесс цикла печати.
Цикл печати

Постраничная разбивка

Платформа хранит большую часть информации о задании печати в структуре 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]--brokenlink--(reference/cprintinfo-class.md#setmaxpage) для структуры CPrintInfo перед отправкой в DoPreparePrinting. Это позволяет указать длину документа.

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

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

Функция-член 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 в диапазон строк и столбцов, которые будут отображаться на этом конкретном листе, а затем соответствующим образом настроить источник окна просмотра.

Print-Time разбиение на страницы

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

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

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

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

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

См. также

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