Многостраничный вывод

Процесс многостраничной печати основан на небольшой хитрости: если процедура обработки события Pri ntPage задает свойству HasMorePages объекта Pri ntPageEventArgs значение True, то объект PrintDocument узнает о наличии дополнительных страниц для печати и автоматически инициирует заново событие PagePri n't.

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

  1. Прочитать строку из поля или из файла.
  2. Не превышает ли длина строки предельное допустимое значение? Если превышает, разбить на несколько фрагментов.
  3. Помещаются ли эти фрагменты на текущей странице?
  4. Если помещаются, напечатать их функцией DrawString начиная с текущей позиции. Если не помещаются, напечатать сколько удастся, начать новую страницу и вывести на ней остальные фрагменты.
  5. Повторить процесс до тех пор, пока не будут обработаны все строки текстового поля или файла.

Однако проверка возможности размещения новой строки на странице не имеет ничего общего с печатью; в ней используются различные метрики, вычисляемые на основании ширины и высоты текстовой строки. В свою очередь, эти параметры зависят от семейства и размера используемого шрифта. К счастью, вы можете положиться на такие методы, как MeasureStri ng; эти методы используют метрики, связанные с текущим контекстом устройства.

 

О классе PrintPageEventArgs

Объект PrintPageEventArgs содержит два ReadOnly-свойства, при помощи которых можно получить информацию о размерах страницы. Значения обоих свойств задаются в сотых долях дюйма.

  • PageBounds: возвращает размеры прямоугольной области всей страницы.
  • MarginBounds: возвращает размеры прямоугольной области, ограниченной полями.
  • В свойстве PageSettings объекта PrintPageEventArgs хранится дополнительная информация. В табл. 8.2 перечислены важнейшие свойства класса PageSetti ngs (большинство принтеров позволяет читать эти свойства, но не все принтеры поддерживают запись).

    Таблица 8.2. Свойства класса PageSettings

    Свойство

    Описание

    Bounds Возвращает размеры страницы с учетом возможной альбомной ориентации печати. Свойство доступно только для чтения
    Color Признак печати страницы в цвете. Логическое свойство, доступное для чтения и записи
    Landscape Ориентация страницы. Логическое свойство, доступное для чтения и записи
    Margins Размеры полей (по умолчанию равны 1 дюйму). Свойство доступно для чтения и записи
    PaperSize Размеры бумаги. Свойство доступно для чтения и записи
    PaperSource Источник бумаги. Свойство доступно для чтения и записи
    PrinterResolution Разрешение принтера. Некоторые принтеры поддерживают нестандартные разрешения, другие позволяют выбирать только между черновой и качественной печатью. Свойство доступно для чтения и записи
    PrinterSettings Настройка принтера для данной страницы. Свойство доступно для чтения и записи

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

    е.PageSettings.Margins = New System.Drawing.Printing.Margins(50.50.50.50)

    Следующий фрагмент начинает печать с левого верхнего края области, ограниченной полями:

    Dim g As Graphics

    g = e.Graphics

    g.DrawImage(PictureBoxl.Image, e.MarginBounds.Left, e.MarginBounds.Top)

     

    Элемент PrintDialog и конфигурация печати

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

    Private Sub Buttonl_Click(ByVal sender As System.Object,_

    ByVal e As System.EventArgs)Handles Buttonl.Click

    Dim PhntDialogl As New PrintDialog()

    ' Следующая строка необходима, потому что информация

    ' объекта PrinterSettings нужна объекту PrintDialog перед выводом

    PrintDialogl.Document = PrintDocumentl

    If PrintDialogl.ShowDialog() = DialogResult.OK Then

    PrintDocumentl. PrintO

    End If

    End Sub

    Выделенная строка сообщает экземпляру PrintOialog, что связанный с ним документ должен быть экземпляром PrintDocumentl (предполагается, что этот объект был создан ранее). Эта строка необходима, поскольку элемент PrintDialog должен получить некоторые параметры печати (в виде объекта Pri ntSetti ngs) перед выводом окна. Чтобы передать ему эту информацию, проще всего назначить объект PrintDocument свойству Document.

     

    Самостоятельное программирование печати

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

    Private Sub ProcedureToDoThePrinting(ByVal Sender As Object,_

    ByVal e As System.Drawing.Printing.PrintPageEventArgs)

    Затем процедура при помощи делегата подключается к событию PrintPage класса PrintDocument. Например, для вызова объекта aPrintDocument класса PrintDocument с приведенной выше процедурой aPri ntDocument_PrintPage используется команда следующего вида:

    AddHandler aPrintDocument.PrintPage, AddressOf Me.aPrintDocument_PrintPage

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

    Private Sub mnuPrint_Click(ByVal sender As System.Object,_

    ByVal e As System.EventArgs)Handles mnuPrint.Click

    Dim aPrintDocument As New PrintDocument()

    AddHandler aPrintDocument.PrintPage.

    AddressOf Me.aPrintDocument_PrintPage

    aPrintDocument.Print()

    End Sub

    Рис. 8.25. Режим предварительного просмотра

    Предварительный просмотр

    Печать простейших документов в VB .NET требует несколько больших усилий, чем в VB6, зато режим предварительного просмотра реализуется гораздо проще. Для этого от вас потребуется лишь назначить объект PrintDocument свойству Document экземпляра PrintPrevl ewDialog. Так, следующий фрагмент почти полностью совпадает с кодом, приведенным выше, однако он реализует предварительный просмотр вместо вывода на принтер. Результаты его выполнения показаны на рис. 8.25:

    Private Sub btnPreview_Click(ByVal sender As System.Object.

    ByVal e As System.EventArgs) Handles btnPreview.Click

    Dim PrintPreviewDialogl As New PrlntPreviewDialog()

    PrintPreviewDlalogl.Document = PrintDocumentl

    If PrintPreviewDialogl.ShowDialog() = DialogResult.OK Then

    PrintDocumentl.Print()

    End If

    End Sub