Многостраничные документы
В этой статье описывается протокол печати Windows и объясняется, как распечатать документы, содержащие более одной страницы. В этой статье рассматриваются следующие разделы:
Протокол печати
Чтобы распечатать документ с несколькими страницами, платформа и представление взаимодействуют следующим образом. Сначала платформа отображает диалоговое окно "Печать", создает контекст устройства для принтера и вызывает функцию члена StartDoc объекта CDC. Затем для каждой страницы документа платформа вызывает функцию CDC
члена StartPage объекта, предписывает объекту представления распечатать страницу и вызывает функцию члена EndPage. Если перед запуском определенной страницы необходимо изменить режим принтера, представление вызывает ResetDC, который обновляет структуру DEVMODE , содержащую сведения о новом режиме принтера. После печати всего документа платформа вызывает функцию-член EndDoc .
Переопределение функций классов представления
Класс CView определяет несколько функций-членов, вызываемых платформой во время печати. Переопределяя эти функции в классе представления, вы предоставляете подключения между логикой печати платформы и логикой печати класса представления. В следующей таблице перечислены эти функции-члены.
Переопределимые функции CView для печати
Имя | Причина переопределения |
---|---|
OnPreparePrinting | Вставка значений в диалоговом окне "Печать", особенно длина документа |
OnBeginPrinting | Выделение шрифтов или других ресурсов GDI |
Onpreparedc | Настройка атрибутов контекста устройства для заданной страницы или разбиение на страницы во время печати |
Onprint | Печать заданной страницы |
OnEndPrinting | Удаление ресурсов 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]-reference/cprintinfo-class.md#setmaxpage) для структуры перед отправкой в нее CPrintInfo
DoPreparePrinting
. Это позволяет указать длину документа.
DoPreparePrinting
Затем отображается диалоговое окно "Печать". При возвращении структура содержит значения, CPrintInfo
указанные пользователем. Если пользователь хочет распечатать только выбранный диапазон страниц, он или она может указать начальные и конечные номера страниц в диалоговом окне "Печать". Платформа извлекает эти значения с помощью GetFromPage
функций GetToPage
CPrintInfo. Если пользователь не указывает диапазон страниц, платформа вызывает 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.
Реализация по умолчанию наборов OnPrepareDC
m_bContinuePrinting значение FALSE , если текущая страница больше 1. Это означает, что если длина документа не указана, платформа предполагает, что документ имеет длину одной страницы. Одним из последствий этого является то, что при вызове версии OnPrepareDC
базового класса необходимо быть осторожным. Не предполагайте, что m_bContinuePrinting будет TRUE после вызова версии базового класса.