* При перепечатке материалов ссылка на www.SeoLiga.ru обязательна!
Компонент PrintDocument
8 февраля 2009
В .NET Framework печатаемый документ представлен компонентом PrintDocument. Хотя у PrintDocument нет графического интерфейса, этот компонент находится на вкладке Windows Forms инструментальной панели Toolbox, откуда его можно пере- тащить на форму приложения, открытую в окне дизайнера.
Объект PrintDocument инкапсулирует всю информацию, необходимую для печа- ти страниц. У него есть ряд свойств: PrinterSettings хранит сведения о возможностях и конфигурации доступных принтеров, Default PageSettings инкапсулирует парамет- ры печати страниц, a PrintCantroller контролирует обработку страниц при печати. Эти свойства позволяют весьма действенно управлять процессом печати. Создание объекта PrintDocument Объект PrintDocument можно создать в период разработки, с помощью графическо- го интерфейса дизайнера, или программно, в период выполнения. В первом случае объект PrintDocument следует перетащить в окно дизайнера прямо с панели Toolbox — в области компонентов появится новый экземпляр этого объекта, автоматически сконфигурированный для работы с системным принтером по умолчанию. Вот как программно создается экземпляр объекта PrintDocument: Visual Basic .NET Dim myPrintDocument As New PrintDocumentO Visual C# PrintDocument myPrintDocument = new PrintDocumentO; Полученный таким образом экземпляр объекта PrintDocument автоматически конфигурируется для работы с системным принтером по умолчанию. Как работает поддержка печати В модели печати, принятой в .NET Framework, печатаемые данные непосредствен- но передаются кодом приложения. Вызов метода Print Document, Print инициирует новое задание печати, попутно генерируя события PrintPage. Если клиентский об- работчик для этого события отсутствует, печать не выполняется. Чтобы задать дан- ные для печати, необходимо написать обработчик для события PrintPage. Если задание печати состоит из нескольких страниц, событие PrintPage генери- руется для каждой из них, поэтому обработчик этого события вызывается много- кратно. Обработчик события PrintPage контролирует исполнение задания печати, обеспечивая последовательный вывод многостраничного документа; без его учас- тия печатались бы лишь несколько копий первой страницы документа. Событие PrintPage Событие PrintPage играет ключевую роль в процессе печати. Чтобы реально отпра- вить данные на принтер, необходимо создать обработчик для события PrintPage и поместить в него код, прорисовывающий печатаемое содержимое. Все данные и объекты, необходимые для печати, передаются обработчику в объекте PrintPage- EventArgs, свойства которого описаны в таблице 8-1, Таблица 8-1. Свойства объекта PrintPageEventArgs Имя Описание Cancel Указывает, отменено ли задание печати Graphics Содержит объект Graphics, формирующий печатаемую страницу HasMorePages Получает или устанавливает значение, указывающее, все ли страницы напечатаны MarginBounds Получает объект Rectangle, представляющий область страницы, ограниченную полями PageBounds Получает объект Rectangle, представляющий страницу целиком PageSettings Получает или устанавливает объект PageSettings для текущей страницы Для преобразования содержимого документа в данные для принтера применя- ется объект Graphics, доступный через класс Print Page EventArgs. В этом случае печа- таемая страница играет ту же роль, что и клиентская области формы, элемента уп- равления и любой другой поверхности для рисования, представленной объектом Graphics. Печатаемую страницу формируют теми же методами, что применяются для прорисовки содержимого формы на экране. Вот пример очень простого метода, который печатает эллипс, вписанный в область, ограниченную полями страницы-. Visual Basic .NET ' Чтобы этот метод был вызван, он должен обрабатывать событие PrintPage. Public Sub PrintEllipse(ByVal sender As System.Object, ByVal e As _ System.Drawing.Printing.PrintPageEventArgs) e.Graphics.DrawEllipse(Pens.Black, e.MarginBounds) End Sub Visual C# // Чтобы этот метод был вызван, он должен обрабатывать событие PrintPage. public void PrintEllipse(object sender, System.Drawing.Printing.PrintPageEventArgs e) i e.Graphics.DrawEllipse(Pens.Black, e.MarginBounds); } Свойства MarginBounds и PageBounds указывают области страницы, доступные для печати. Можно границами области печати сделать поля страницы, вычислив координаты печатаемых объектов на основе прямоугольника MarginBounds. Допус- тимо печатать и за пределами страничных полей — например, чтобы создать верх- ний и нижний колонтитулы. Для этого следует рассчитывать координаты объектов на основе прямоугольника PageBounds, Как и при выводе на дисплей, при печати координаты по умолчанию исчисляются в пикселах. Свойство HasMorePages позволяет указать, является ли задание печати много- страничным. По умолчанию это свойство установлено и false. Если же потребуется напечатать многостраничный документ, следует установить его в true, а по заверше- нии печати последней страницы — снова в false. Примечание Обработчик события PrintPage должен следить за числом страниц за- дания печати, в противном случае результаты будут непредсказуемыми. Скажем, если по завершении вывода последней страницы не установить свойство HasMore- Pages в false, приложение будет генерировать события PrintPage снова и снова. Кроме того, предусмотрена возможность отменить задание печати, не дожида- ясь окончания вывода текущей страницы. Для этого следует установить свойство Cancel в true. Чтобы создать обработчик события PrintPage, дважды щелкните экземпляр Print- Document в окне дизайнера (так создается обработчик по умолчанию) либо объяви- те обработчик вручную (см. главу 3). Вывод на печать Чтобы создать задание печати, достаточно вызвать метод Print Document, Print. В сле- дующем разделе вы узнаете, как написать код, который определяет тип содержимо- го, предназначенного для вывода на печать. Печать графики Печатать графические элементы не сложнее, чем рисовать их на экране. Для обеих целей применяют объект Graphic, доступный через объект PrintPageEventArgs. Печа- тают как простые фигуры, так и более сложные; в последнем случае используют объект GraphicsPath. Вот как напечатать сложную фигуру с помощью объекта Graphics Path: Visual Basic .NET Этот метод должен обрабатывать событие PrintPage. Public Sub PrintGraphicsfByVal Sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Dim myPath As New System.Drawing.Drawing2D.GraphicsPath() myPath.AddPolygon(New Point() {New Point(1, 1), New Point(12, 55), New Point(34, 8), New Point(52, 53), New Point(99, 5)M myPath.AddRectangle(New Rectangle(33, 43, 20, 20)) e.Graphics.DrawPath(Pens.Black, rnyPath) End Sub Visual C# // Этот метод должен обрабатывать событие PrintPage. public void PrintGraphics(object sender, System.Drawing.Printing.PrintPageEventArgs e) { System.Drawing.Drawing2D.GraphicsPath myPath = new System.Drawing.Drawing2D.GraphicsPath(); myPath.AddPolygon(new Point[] {new Point(1, 1). new Point(12, 55), new Point(34, 8), new Point(52, 53), new Point{99, 5)}); myPath.AddRectangle(new Rectangle(33, 43, 20, 20)); e.Graphics.DrawPath(Pens.Black, myPath): } Чтобы напечатать многостраничный графический документ, следует вручную разбить его на страницы и написать соответствующий код. Следующий метод раз- бивает при печати эллипс, не умещающийся на одной странице, на две страницы: Visual Basic .NET Dim FirstPagePrinted As Boolean = False ' Этот метод должен обработать событие PrintPage Public Sub PrintBigEllipse(ByVal Sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) If FirstPagePrinted = False Then FirstPagePrinted = True e.HasMorePages = True e.Graphics.DrawEllipse(Pens.Black, New Rectangle(0, 0, e.PageBounds.Width, e.PageBounds.Height * 2)) Else e.HasMorePages = False FirstPagePrinted = False e.Graphics.DrawEllipse(Pens.Black, New Rectangle(0, -(e.PageBounds.Height), e.PageBounds.Width, e.PageBounds. Height * 2)) End If End Sub Visual C# bool FirstPagePrinted = false; // Этот метод должен обработать событие PrintPage public void PrintBigEllipse(object sender, System. Drawing. Print ing. PrintPageEventA^gs e) I if (FirstPagePrinted == false) { FirstPagePrinted - true: e. HasMorePages - true; e, Graphics. DrawEllipse(Pens. Black, new Rectangle(0, e.PageBounds. Width, e. PageBounds. Height * 2)); else e. HasMorePages = false; FirstPagePrinted = false; e. Graphics, DrawEllipse(Pens. Black, new Rectangle(0, -(e. PageBounds. Height), e. PageBounds. Width, e, PageBounds. Height * 2)); В этом примере управление вывода страниц на печать реализовано с помощью переменной FirstPagePrinted. Заметьте: эта переменная объявлена вне метода. Если объявить ее внутри метода, она инициализируется при каждом его вызове и всегда возвращает false. В действительности при печати каждой страницы программа пе- рерисовывает эллипс заново, меняя его положение так, чтобы на текущую страни- цу попала соответствующая часть фигуры. Печать текста Вывод на печать текста происходит так же, как на экран, — с помощью метода Graphics. DrawString. Как и при выводе на экран, необходимо указать шрифт, сам текст, объект Brush и координаты начала печати, например: Visual Basic .NET Dini mytont As New Font( "Batang", 36. FontStyle. Regular, GraphicsUnit. Pixel) Dim Hello As String = "Hello World!" e. Graphics. DrawString(Hello, inyfont Brushes. Black, 30. 30) Visual C# Font myfont = new Font("Batang", 36. FontStyle. Regular, GraphicsUnit. Pixel); Примечание Перед печатью текста следует программно проверить, не выходит ли какая-то его часть за границы страницы: любое содержимое, которое выходит за границы страницы, напечатано не будет. Печать многострочного текста Для печати многострочного текста, например массива строк или содержимого тек- стового файла, необходим код, вычисляющий расстояние между отдельными стро- ками. Чтобы рассчитать число строк на странице, разделите высоту клиентской области страницы (она равна высоте страницы за вычетом полей) на кегль шрифта. Положение любой строки на странице можно вычислить, умножив ее номер на кегль шрифта. Следующий пример демонстрирует печать строкового массива с име- нем myStrings: Visual Basic .NET Эта переменная отслеживает текущий элемент массива, Во избежание инициализации этой переменной при печати каждой страницы, ее следует объявлять вне обработчика события PrintPage. D:i.m ArrayCounter As Integer = 0 Это обработчик события PrintDocument.PrintPage. Он предполагает, что строковый массив с именем myStringsO уже объявлен и заполнен, а также что инициализирован объект myFont, представляющий выбранный для печати шрифт Private Sub PrintStrings{sender As Object, e As PrintPageEventArgs) Объявить переменные, управляющие межстрочными интервалами и разбиением документа на страницы. Dim LeftMargin As Single = e.MarginBounds.Lefi Dim TopMargin As Single = e.MarginBounds.Top Dim MyLines As Single - 0 Dim YPosition As Single = 0 Dim Counter As Integer = 0 Dim CurrentLine As String Подсчитать число строк на странице, MyLines = e.MarginBounds.Height / nyFont.GetHeight(e.Graphics) Распечатать все строки файла, останавливаясь в конце страниц. While Counter < MyLines And ArrayCounter <- myStrings.GetUpperBound(O) CurrentLine = myStrings(ArrayCounter) YPosition - TopMargin + Counter * myFont.GetHeight(e.Graphics) e.Graphics.DrawString(Cur rent Line, myFont. Brushes.Black, LeftMargin, YPosition, New StringFormatO) Counter += 1 ArrayCounter += 1 End While 1 Если напечатаны еще не все строки, печатать следующую страницу. If Not (ArrayCounter = myStrings.GetUpperBound(O)) Then e.HasMorePages = True Else e.HasMorePages - False End If End Sub Visual C# // Эта переменная отслеживает текущий элемент массива. // Во избежание инициализации этой переменной при печати каждой // страницы, следует объявлять ее вне обработчика события PrintPage. int ArrayCounter = 0; // Это обработчик события PrintDocument.PrintPage. Он предполагает, // что строковый массив с именем rnyStrings() уже объявлен и заполнен, // а также что инициализирован объект myFont, представляющий // выбранный для печати шрифт. private void PrintStrings(object sender, PrintPageEventArgs e) ! // Объявить переменные, управляющие межстрочными // интервалами и эазбиением документа на страницы.- float LeftMargin - e.MarginBounds.Left; float TopMargin = e.MarginBounds.Top; float MyLines = 0; float YPosition - 0; int Counter = 0; string CurrentLine; // Подсчитать число строк на странице. MyLines = e.MarginBounds.Height / myFont.GetHeight(e.Graphics); // Распечатать все строки файла, останавливаясь в конце страниц. while (Counter < MyLines && ArrayCounter <= mySt rings. Ge.tUpperBound(O)) I CurrentLine = myStrings[ArrayCounter]; YPosition = TopMargin + Counter * myFont.GetHeight(e.Graphics); e.Graphics.DrawString(CurrentLine, myFont, Brushes.Black, LeftMargin, YPosition, new StringFormatO); Counter ++; ArrayCounter ++; // Если напечатаны еще не все строки, печатать следующую страницу, if ( ! (ArrayCounter == rnyStrings.GetUpperBound(O))) e.HasMorePages = true; else e, HasMorePages = false; Работа с цветами Набор параметров для печати на принтере, поддерживающем цвета, отличается от того, что требуется для печати на черно-белом принтере. При цветной печати необ- ходимо учесть, что некоторые цвета, хорошо различимые на экране, практически не видны на бумаге. Таким образом, код для печати на черно-белых и цветных прин- терах не одинаков. Чтобы определить, поддерживает ли текущий принтер цветную печать, проверь- те свойство PrinterSettings.SupportsColor. Если этот так, свойство DefauItPageSettings. Color установлено в true, а принтер будет настроен на цветную печать по умол- чанию. Для черно-белой печати установите свойство Default PageSettings. Color ъ false. Следующий пример демонстрирует организацию поддержки цветной и черно-бе- лой печати с помощью свойства PrinterSettings.SupportsColor. Visual Basic .NET Этот пример предполагает наличие операторов Irnports System. Drawing, System. Drawing. Drawing2D и System. Drawing. Printing Dim BrushOne As Brush Dim BrushTwo As Brush If PrintDocumentl. PrinterSettings.SupportsColor = True Then Создать кисти для цветной печати, BrushOne = Brushes. Red BrushTwo = Brushes. Blue Else Создать объекты HatchedBrush для черно-белой печати. BrushOne = New HatchBrush(HatchStyle.DarkVertical, Color. Black) BrushTwo = New HatchBrush(HatchStyle.DashedHorizontal, Color. Black) End If Visual C# // Этот пример предполагает наличие операторов Irnports System. Drawing, // System. Drawing. Drawing2D и System. Drawing. Printing Brush BrushOne; Brush BrushTwo; if (PrintDocumentl. PrinterSettings.SupportsColor == true) { // Создать кисти для цветной печати. BrushOne = Brushes. Red; BrushTwo = Brushes. Blue; else // Создать объекты Hatched В rush для черно-белой печати. BrushOne - new HatchBrushfHatchStyle. DarkVertical, Color. Black); BrushTwo = new HatchBrush(HatchStyle. DashedHorizontal, Color. Black): i ^ Организация поддержки печати в приложении 1. Перетащите объект Print Document с панели Toolbox в окно дизайнера — в облас- ти компонентов появится новый экземпляр этого компонента, автоматически настроенный для использования принтера по умолчанию. Создать компонент Print Document можно и программно. 2. Напишите обработчик для события PrintDocument PrintPage. 3. Добавьте к обработчику события PrintPage код, рисующий содержимое в клиент- ской области страницы. Передайте сформированное изображение на принтер с помощью объекта Print Page Event Args. Graphics. 4. Если вы работаете с многостраничными документами, напишите код, управля- ющий разбиением на страницы.