Глава 9
Печать документов
Многие разработчики сталкиваются с необходимостью организации печати из приложения текстовых документов или графики. Среда разработки Delphi предоставляет для решения этой задачи достаточно простой в использовании и эффективный инструментарий.
Механизм печати содержится в специальном модуле printers. раs. Достаточно добавить его в секцию uses приложения и ваша программа готова к взаимодействию с принтером. Для организации печати в исходном коде применяется класс Tprinter, свойства и методы которого обеспечивают доступ к принтерам, установленным в системе.
При помощи этого класса программист может распечатывать в своем приложении не только тексты, но и растровые изображения и графические элементы.
Настроить принтер можно при помощи специального компонента в составе VCL — стандартного системного диалога настройки принтера
TPrinterSetupDialog.
В этой главе рассматриваются следующие вопросы:
Класс TPrinter
Каждое приложение, в котором используется принтер, должно содержать в секции uses модуль printers. Если ссылка на данный модуль имеется, то при выполнении приложения автоматически создается экземпляр класса Tprinter, предоставляющий программисту все необходимые средства для организации вывода данных на один из подключенных к компьютеру принтеров. Рассмотрим свойства и методы класса Tprinter.
Таблица 9.1. Свойства и методы класса Tрrinter
Объявление |
Описание |
property Aborted: Boolean; |
Определяет, было ли задание на печать удалено пользователем. Если задание удалено — возвращает значение True |
property Canvas: TCanvas ; |
Канва принтера (см. главу 8). Предоставляет пользователю возможность определить значения свойств Brush, Font и Pen для печати графики на принтере |
TPrinterCapability = (pcCopies, pcOrienta-tion, pcCollation); TPrinterCapabilities = set of TPrinterCapability; |
Содержит текущие установки драйвера принтера: PcCopies — количество копий; PcOrientation — ориентация листа; |
property Copies: Integer; |
Указывает требуемое количество копий документа |
property Fonts: TStrings ; |
Содержит список имен всех шрифтов, поддерживаемых текущим принтером |
property Handle: HDC; |
Контекст устройства. Применяется при вызове из программы функций Windows API |
TPrinterOrientation = (poPortrait, poLand-scape) ; |
Определяет ориентацию листа бумаги: PoPortrait - вертикальная; |
property Orientation: TPrinterOrientation; |
PoLandscape — горизонтальная |
property PageHeight: Integer; |
Содержит высоту страницы в пикселах |
property PageNuinber: Integer; |
Содержит номер текущей страницы |
property PageWidth: Integer; |
Возвращает значение ширины страницы в пикселах |
property Printerlndex: Integer; |
Индекс имени текущего принтера в списке Printers |
property Printers: TStrings; |
Содержит список установленных в системе принтеров |
property Printing: Boolean; |
Имеет значение True до тех пор, пока продолжается процесс печати |
property Title: String; |
Строка, идентифицирующая печатаемый документ в окне состояния текущего принтера |
property Capabilities: TPrinterCapabilities; |
PcCollation - включен или нет параметр разбора по копиям |
procedure Abort; |
Метод прерывает процесс печати, и принтер приступает к обработке следующего задания. При этом значение свойства Aborted устанавливается равным True |
procedure BeginDoc; |
Начинает выполнение нового задания печати |
procedure EndDoc; |
Завершает печать документа, очищает буфер принтера и, если необходимо, прокручивает последнюю страницу. Этот метод не следует вызывать, если печать была прервана методом Abort |
procedure NewPage; |
Инициализирует печать с новой страницы. Значение свойства PageNumber при этом увеличивается на единицу |
Обращаем внимание читателя на то, что большинство свойств (Fonts, Handle, PageWidth, PageHeight, Aborted, Printing, Capabilities И Др.) доступны только для чтения.
Для создания и обращения к экземпляру класса TPrinter используется объявленная В Модуле Printers функция
function Printer: TPrinter;
Она возвращает указатель на созданный экземпляр класса.
Как видно из таблицы 9.1, класс TPrinter не только обеспечивает доступ к параметрам текущего принтера, но и создает индексированный список printers имен всех доступных принтеров системы. Любой принтер из списка можно сделать активным при помощи свойства printerindex.
Управление печатью осуществляется описанными в таблице методами Abort, BeginDoc, EndDoc И NewPage. Очень важную роль играет свойство canvas, представляющее собой канву принтера (см. главу 8). С ее помощью принтер можно использовать для рисования или вывода текстов так же, как и формы или любые другие компоненты, имеющие канву.
Печать текстов
С точки зрения программиста простейший способ печати текстов из приложений Delphi не изменился со времен ранних версий Turbo Pascal. Для печати используются процедуры write и writein, которым в качестве устройства вывода назначается принтер.
Решим простейшую задачу — напечатаем на принтере сакраментальную фразу “Hello, printer!” (что поделать — традиция). Для этого создадим консольное приложение (пункт меню File/New) и добавим следующий исходный код (не забудьте о необходимости добавить в секцию uses модуль Printers):
program Project1;
{$APPTYPE CONSOLE} uses SysUtils, Printers;
var FPrint: TextFile;
begin
AssignPrnfFPrint);
Rewrite(FPrint);
Writeln(FPrint,'Hello Printer!');
CloseFile(FPrint);
end.
Процедура Assignprn из модуля printers связывает текстовую файловую переменную с текущим принтером системы и создает буфер вывода в памяти. Оператор Rewrite открывает устройство вывода. Процедура Writein осуществляет печать строки и переводит позицию печати на новую строку (процедура write в отличие от Writein переход на новую строку не делает). И наконец, процедура CloseFile завершает печать и разрывает связь файловой переменной и принтера (рис. 9.1).
Рис. 9.1. Главная форма проекта DemoPrint
Подробнее об использовании файловых переменных и процедур ввода/вывода рассказывается в главе 6.
В одном операторе write или writein можно вывести несколько значений разных типов — целые числа, переменные с плавающей точкой и т. д. Для этого значения или переменные разделяются запятыми.
Кроме этого, в составе переменных вывода могут быть текстовые строки объектов TSrings И TStringList.
В качестве примера рассмотрим небольшой проект DemoPrint. В нем при помощи диалога открытия файла выбирается нужный файл. В зависимости от состояния группы переключателей RadioGrp, вывод файла направляется на экран в компонент тмето или непосредственно на принтер.
При щелчке на кнопке printBtn содержимое компонента тмето выводится на принтер (листинг 9.1.).
Листинг 9.1. Секция implementation модуля главной формы проекта DemoPrint
implementation uses printers;
{$R *.DFM}
procedure TMainForm.DirectPrint;
var FileTxt, PrintTxt: TextFile;
TempStr: String;
begin
AssignFile(FileTxt, OpenDlg.FileName);
AssignPrn(PrintTxt);
Reset(FileTxt);
Rewrite(PrintTxt);
while Not EOF(FileTxt) do
begin Readin(FileTxt, TempStr);
Writein(PrintTxt, TempStr)
end;
CloseFile(FileTxt);
CloseFile(PrintTxt);
end;
procedure TMainForm.OpenBtnClick(Sender: TObject);
begin
if Not OpenDIg.Execute then Exit;
if RadioGrp.Itemlndex = 0
then Memol.Lines.LoadFromFile(OpenDIg.FileName)
else DirectPrint;
end;
procedure TMainForm.PrintBtnClick(Sender: TObject);
var PrintTxt: TextFile;
i: Integer;
begin
AssignPrn(PrintTxt);
Rewrite(PrintTxt);
for i :=0 to Memol.Lines.Count -1 do Writeln(PrintTxt, Memol.Lines[i]);
CloseFile(PrintTxt);
end;
procedure TMainForrn.RadioGrpClick (Sender: TObject);
begin PrintBtn.Enabled := RadioGrp.Itemlndex = 0;
end;
end.
Процедура DirectPrint обеспечивает прямой вывод текстового файла на принтер. Для этого две файловые переменные связываются с выбранным файлом и принтером. Прочитанная из файла строка сразу же отправляется на принтер.
Метод-обработчик PrintBtnClick обеспечивает вывод на печать строк из компонента ТМето. Для этого каждая строка из индексированного списка строк (свойство Lines) печатается процедурой writein. Файловая переменная Fprint настроена на текущий принтер.
Метод-обработчик RadioGrpciick обеспечивает отключение кнопки печати файла при переключении устройства вывода на принтер.
Для управления печатью можно использовать следующие управляющие символы:
Write(FPrint, 'После этой строки произойдет переход на новую строку', #10, #13);
Writein (FPrint, 'После этой строки включится прогон страницы',^L);
При печати текстового файла по умолчанию используется шрифт System размером 10. Для изменения параметров шрифта (в том числе и во время печати) используется свойство canvas объекта printer. Это может выглядеть так:
with Printer.Canvas.Font do
begin
Name := 'Arial';
Size := 12;
end;
Печать графики
При печати графики используется свойство canvas типа TCanvas экземпляра класса Tprinter из модуля printers. Класс канвы обладает богатым набором возможностей по отображению разнообразных графических элементов и растровых изображений. Подробно свойства и методы канвы обсуждаются в главе 8, поэтому заинтересованный читатель может обратиться к ней, а здесь мы остановимся только на особенностях печати графики.
Особенности реализации процесса передачи графики из канвы на принтер скрыты от разработчика. Для обеспечения печати необходимо выполнить следующую последовательность действий:
Обратите внимание, что обращение к канве принтера выполняется только после начала печати. Иначе возникает ошибка времени выполнения.
При переносе содержимого канвы на лист бумаги вид напечатанной копии сильно зависит от параметров принтера. Поэтому перед печатью желательно проверять размер изображения и при необходимости проводить его масштабирование. Оно выполняется не только при слишком больших картинках, но и при необходимости увеличить небольшое изображение до размеров листа.
Размер листа бумаги для текущего принтера определяется свойствами PageHeight и PageWidth класса TPrinter.
Кроме этого, качество представления графики (разрешение) для экрана и принтера могут существенно различаться. Текущее разрешение принтера можно узнать при помощи функции Windows API GetDeviceCaps, которая возвращает значения масштаба по горизонтали и вертикали, соответствующих числу логических пикселов на дюйм для используемого по умолчанию принтера.
Примеры реализации программного кода для печати графики приведены ниже.
Печать растровых изображений
Для печати растрового изображения необходимо загрузить его в экземпляр класса TBitmap или его наследника. Проще всего использовать в приложении компонент Timage или созданный самостоятельно объект типа TBitmap. Затем изображение передается на канву принтера при помощи стандартных методов и класс TPrinter обеспечивает его печать.
Например, печать изображения в центре страницы без изменения масштаба может быть реализована так:
procedure TForml.ButtonlClick(Sender: TObject);
begin
with Printer, Imagel do
begin
if (Picture.Width > PageWidth) or(Picture.Height > PageHeight) then begin
ShowMessage('Изображение больше страницы');
Exit;
end;
BeginDoc;
Canvas.Draw((PageWidth - Picture.Width) div 2,(PageHeight - Picture.Height) div 2, Picture.Bitmap);
EndDoc;
end;
end;
Если изображение помещается на страницу, то метод Canvas. Draw обеспечивает вывод изображения по центру страницы.
Для непропорционального масштабирования изображения по размерам страницы можно сделать так:
procedure TFormI.ButtonlClick(Sender: TObject);
var ImageRect: TRect;
begin
with Printer, Imagel do
begin
ImageRect.Top := 0;
ImageRect.Left := 0;
ImageRect.Right :- PageWidth;
ImageRect.Bottom := PageHeight;
BeginDoc;
Canvas.StretchDraw(ImageRect, Picture.Bitmap);
EndDoc;
end;
end;
В этом случае всю работу по масштабированию выполняет метод StretchDraw канвы, который изменяет размеры изображения в соответствии с размерами прямоугольника ImageRect.
Для пропорционального масштабирования необходимо провести элементарные вычисления по расчету размеров сторон прямоугольника. Исчерпывающий пример есть в поставке Delphi: папка heip\examples\jpeg.
Печать графических примитивов
Печатать произвольные графические фигуры и текст как графику можно и без создания растровых изображений, а непосредственно с использованием возможностей свойства Canvas объекта printer.
procedure TFormI.ButtonlClick(Sender: TObject);
var R: TRect;
P: TPoint;
begin
Printer.BeginDoc;
with Printer.Canvas do begin Pen.Color := clBlack;
Brush.Color := clBlue;
Brush.Style := bsCross;
Font.Size := 14;
R := Rect( 10, 10, 160, 160);
Ellipse(R.Left, R.Top, R.Right, R.Bottom);
P := Point(60, 180);
TextOut (P.X, P.Y, 'Ellipse');
end;
Printer.EndDoc;
end;
При выполнении данного кода на принтере должен напечататься круг с подписью "Ellipse" под ним. Обратите внимание, что в этом случае текст под рисунком печатается при помощи графических средств.
Свойство canvas класса TPrinter позволяет реализовывать еще одну интересную возможность: содержимое канвы формы или другого визуального компонента можно распечатать без особых хлопот.
Предположим, что при визуализации формы на ее канве отображается некий геометрический рисунок.
Рис. 9.2. Геометрический рисунок на канве формы
Для его создания используются свойства и методы класса TCanvas. В приложении DemoPrintCanvas (рис. 9.2) для создания рисунка используется метод-обработчик OnPaint.
Чтобы направить этот рисунок на печать, достаточно скопировать прямоугольник нужного размера из канвы формы в канву принтера. В листинге 9.2. это делается в методе-обработчике printBtnclick при помощи метода CopyRect.
Листинг 9.2 Секция implementation модуля главной формы проекта DemoPrintCanvas
implementation
{$R *.DFM)
uses Printers;
procedure TMainForm.FormPaint(Sender: TObject);
begin with Canvas do begin Pen.Color := clBlack;
Pen.Width :=2;
Brush.Color := clWhite;
Brush.Style := bsClear;
Font.Size := 14;
Ellipse( 10, 10, 160, 160 );
Brush.Color := clRed;
Ellipse( 60, 60, 110, 110);
Brush.Color := clBlue;
Brush.Style := bsFDiagonal;
Ellipse( 17, 35, 153, 75);
Brush.Color := clBlue;
Brush.Style := bsBDiagonal;
Ellipse; 16, 85, 154, 135);
Text0ut(50, 180, 'Нечто');
end;
end;
procedure TMainForm.PrintBtnClick(Sender: TObject);
var ImageRect: TRect;
begin ImageRect := Rect(10, 10, 160 , 200);
with Printer do begin BeginDoc;
Canvas.CopyRect(ImageRect, MainForm.Canvas, ImageRect);
EndDoc;
end;
end;
end.
Печать формы и элементов управления
В данном пункте мы освоим полезную и в то же время простую операцию,
позволяющую напечатать форму в том виде, как она выглядит на экране.
Для ее реализации следует вызвать метод print формы. При этом включать в секцию uses модуль printers не нужно.
Метод класса TForm
procedure Print;
работает следующим образом. Он копирует клиентскую область текущего окна во внеэкранное растровое изображение, а затем печатает его с помощью функции Windows API stretchDiBits. Для управления режимом масштабируемой копии используется свойство
type TPrintScale = (poNone, poProportional, poPrintToFit) ;
property PrintScale: TPrintScale;
Значения свойства имеют такой смысл:
Есть и другой путь печати как форм, так и любых других элементов управления — наследников класса TwinControl. У всех оконных элементов управления есть метод paintTo, позволяющий отрисовывать "себя" на любой канве. В нашем случае это канва принтера.
Контроль ошибок печати
Для повышения надежности приложений при работе с принтером применяется специальный класс исключительной ситуации EPrinter, происходящий непосредственно от базовой исключительной ситуации Exception. Поэтому класс EPrinter обладает стандартным набором свойств и методов (см. главу 4).
Применяется он также стандартным образом, внутри блока try ... except:
with Printer do try
BeginDoc;
Canvas.TextOut(100, 100, 'SomeTexf );
EndDoc;
except
on E: EPrinter do ShowMessage('Ошибка печати');
end;
Резюме
В данной главе рассмотрены вопросы, связанные с организацией вывода на печать текстов, списков строк, форм, растровых изображений и произвольных графических объектов. Определяющую роль в этих процессах играет модуль printers, описывающий класс TPrinter. Экземпляр класса доступен разработчику через функцию Printer.
Печать текстов основана на хорошо известных процедурах ввода/вывода, перед использованием которых необходимо связать файловую переменную с текущим принтером при помощи метода Assignprn.
Печать графики основывается на использовании возможностей класса TCanvas, доступного в объекте типа TPrinter через свойство Canvas.
При изучении этой главы полезно вспомнить материал следующих глав: