Печать
Печать в .NET – дело непростое, однако богатство возможностей окупает все хлопоты. В этом разделе мы подробно опишем процесс печати одной страницы (в основном на примере автоматически сгенерированного кода), а затем покажем, как напечатать несколько страниц. Также будет показано, как запрограммировать собственную процедуру печати с использованием делегата. Начнем с печати изображения, хранящегося в графическом поле.
Примечание
Чтобы обойти некоторые ограничения, действующие в GDI+, мы будем предполагать, что изображение задается свойством Image, а не прямым копированием в графическое поле.
Печать в конечном счете сводится к выводу информации в графическом контексте, но вместо экранного контекста используется контекст, ассоциированный с принтером или окном предварительного просмотра печати.
Как при выводе на принтер, так и при использовании поддержки предварительного просмотра (Print Preview) в .NET работа всегда начинается с создания объекта класса System.Drawing.Printing.PrintDocument. Для получения этого объекта можно применить один из следующих способов:
- Воспользоваться элементом PrintDocument на панели элементов и положиться на автоматически сгенерированный код или воспользоваться оператором New в конструкции вида:
Dim aPrintDocument As New PrintDocument()
- Присвоить значение свойства Document экземпляра класса объекту, объявленному с типом PrintDocument.
При использовании панели элементов на форме размещается элемент PrintDocument, не обладающий визуальным интерфейсом. При этом генерируется фрагмент следующего вида:
Friend WithEvents PrintDocumentl As System.Drawing.Printing.PrintDocument
Непосредственное создание экземпляра происходит в следующей строке, включенной в процедуру InitializeComponent:
Me.PrintDocumentl = New System.Drawing.Printing.PrintDocument()
Объявление объекта PrintDocument с ключевым словом WithEvents играет важнейшую роль для понимания автоматически сгенерированного кода печати. Дело в том, что при вызове метода Print для экземпляра класса PrintDocument .NET инициирует по крайней мере три события:
- BeginPrint;
- PrintPage (при печати нескольких страниц может инициироваться многократно);
- EndPrint.
Минимальная поддержка печати в программе требует программирования как минимум со бытия PrintPage.
Примечание
При необходимости можно запрограммировать обработчики и для двух других событий, но фактическая печать выполняется именно в обработчике PrintPage. Два других события обычно используются для оповещения о начале и завершении печати.
Во втором параметре события PrintPage передается объект PagePrintEventArgs. В этом объекте хранится много полезных данных, в том числе:
- Графический объект, определяемый значением свойства Graphics. С этим объектом выполняются все операции вывода, и его содержимое будет в итоге напечатано на принтере.
- Объект PageSettings содержит инструкции, относящиеся к печати страниц. Среди свойств этого объекта – признак печати в альбомной (landscape) ориентации, разрешение принтера, размеры полей и т. д.
В следующем простом примере при нажатии кнопки вызывается метод Print класса PrintDocument:
Private Sub Buttonl_Click(ByVal sender As System.Object,_ ByVal e As System.EventArgs) Handles Buttonl.Click PrintDocumentl.Print() End Sub
Метод Print вызывает событие PrintPage, поэтому на следующем этапе следует запрограммировать обработчик события PrintDocumentl_PrintPage, в котором и происходит непосредственная печать. Если обработчик был сгенерирован с помощью дизайнера, в заголовок автоматически включается соответствующая секция Handles:
1 Private Sub Pri ntDocumentl_PrintPage( ByVal sender As System.Object. ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage 2 Dim g As Graphics 3 g = e.Graphics 4 g.DrawImageCPictureBoxl.Image. 0. 0) 5 g.Dispose() 6 e.HasMorePages = False 7 End Sub
При выполнении этого фрагмента изображение печатается на принтере по умолчанию (о том, как сменить принтер, будет рассказано в следующем разделе). Хотя наш пример относительно прост, каждая строка в нем играет важную роль и заслуживает объяснения. В строке 1 событие связывается с процедурой, имеющей правильную сигнатуру, не требуя от вас прямого использования делегата (см. главу 6).
В строке 3 мы получаем объект Graphics, представляющий поверхность вывода текущего принтера. Строка 4 выводит изображение начиная с левого верхнего угла. Вывод происходит на принтере, с которым связан графический контекст. Присутствие вызова Dispose в строке 5 связано с тем, что графические контексты (как было сказано выше) не освобождаются сборщиком мусора. Строка 6 сообщает об отсутствии дальнейших страниц для печати.