Печать отчетов
Любое приложение по работе с базами данных можно считать неполным, если в приложении не реализована печать данных. Если во многих других приложениях без печати можно обойтись, а в некоторых из них это все лишь красивый маркетинг, то приложениями для работы с базами данных, у которых отсутствует печать, редко кто будет пользоваться.
В Delphi7 для предварительного просмотра и печати отчетов существует достаточный набор компонентов под названием QuickReport.
Надо заметить, что раздел справки по этой теме, находящийся в файле «c:\Program Files\Borland\Delphi7\Help\QUICKRPT.HLP», достаточно скудный. Исходных модулей по данным компонентам тоже нет. Все компоненты расположены в откомпилированных файлах ‘dcu’. Поэтому необходимо привести начальные шаги по использованию имеющихся возможностей печати в Delphi7. Здесь, и в дальнейшем упоминается путь по умолчанию «c:\Program Files\Borland\Delphi7».
Начать следует с того, чтобы проверить факт установки компонентов этой группы. Для этого можно воспользоваться подпунктом главного меню View-Component List, и попробовать там найти, например, компонент TQuickRep.
В большинстве случаев, при установке по умолчанию, нужный пакет не установлен. Об этом также упомянуто в файле: «c:\Program Files\Borland\Delphi7\Demos\Quickrpt\QReport_README.txt», в этом файле также описан и процесс установки.
Для того, чтобы установить пакет нужно выполнить следующие действия.
В главном меню Delphi7 выбираем пункт «Component», а в нем подпункт «Install Packages». В открывшемся диалоговом окне выбираем кнопку “Add”, находим в “bin”-директории Delphi (...\Borland\Delphi7\bin) файл “dclqrt70.bpl”.
После установки, в конце палитры компонентов появится вкладка QReport; а также в репозитории, на вкладке New – элемент Report.
Вкладку можно переместить в удобное для работы место, как и сами компоненты на вкладке. Для этого в главном меню Delphi7 выбираем пункт «Component», а в нем подпункт «Configure Palette», и выполняем нужные действия.
Формирование отчета можно начинать двумя путями. Либо разместить на форме компонент QuickRep с вкладки QReport, либо использовать элемент Report из Репозитория. Для работы практичнее использовать второй вариант.
Оба элемента построены на базе одного класса – TquickRep. Однако во время выполнения, содержимое компонента QuickRep на форме будет выглядеть почти также как в конструкторе. А для отображения самого отчета нужно выполнить еще некоторые действия. Так, при вызове кода QuickRep1.Preview (например, в обработчике события кнопки), предварительный просмотр отчета все равно будет показан совершенно в отдельном окне. Поэтому во время выполнения, демонстрация формы с расположенным на ней компонентом QuickRep не несет какой-либо конструктивности. При втором варианте для данного компонента во время дизайна создается своя форма, где можно настроить внешний вид отчета. А его использование, как уже упоминалось, выполняется другими методами.
Во время работы программы, непосредственно в окне отчета можно просматривать собранную информацию из базы данных – перелистывая страницы, меняя масштаб просмотра. И непосредственно из этого окна можно выполнять печать. Также печать можно выполнить вызовом кода: QuickRep1.Print
При двойном щелчке по компоненту QuickRep в режиме конструктора можно настроить свойства будущего документа: размер бумаги, поля и т.д. Что равносильно выбору пункта Report Setting из контекстного меню компонента.
ПРИМЕР
Будем использовать элемент Report из Репозитория. По умолчанию имеет имя QuickReport2.
Помещаем на него (в любое место) компонент Table с вкладки BDE.
Для дальнейшей работы воспользуемся демонстрационными примерами баз данных, устанавливаемых вместе с Delphi.
Настраиваем свойства компонента Table1: DatebaseName выставляем в ‘DBDEMOS’, TableName в ‘animals.dbf’, Active в ‘true’.
На вкладке QReport берем компонент QRBand и помещаем на QuickReport2.
Меняем свойство BandType у компонента QRBand на rbDetail.
Помещаем на этот полосу компонент QRDBText.
Настраиваем у него свойство DataSet в ‘Table1’, DataField в ’NAME’.
Помещаем на полосу компонент QRDBImage.
Настраиваем у него свойство DataSet в ‘Table1’ DataField в ‘BMP’.
Из контекстного меню QuickReport2 выбираем пункт Preview (в режиме конструктора). Аналогично (в режиме выполнения) можно выполнить код
QuickRep1.Preview. Не забываем подключить Unit2.
В результате отобразится окно предварительного просмотра данных. Но в нем отображается только первая запись из набора данных.
Для того, чтобы увидеть весь набор нужно у самого компонента QuickReport2 настроить свойство DataSet в ‘Table1’.
Вот так, достаточно просто можно работать с компонентами QuickReport.
Несколько советов по дальнейшей работе.
В отношении свойства BandType компонента QRBand.
– По умолчанию имеет тип rbTitle (полоса заголовка). Появляется только на первой странице.
– rbColumnHeader (полоса заголовков столбцов) отображается на каждой странице.
Для отображения информации на указанных полосах обычно используют компонент QRLabel (компонент Label с вкладки Standart – не отображается).
– rbDetail (полоса деталей). Как было показано в примере – выводит весь набор из базы данных.
Вообще, реализуется достаточно большой набор полос. Есть колонтитулы, итоговые полосы и т.д. Полоса с указанным типом, после помещения ее на компонент QuickReport, сразу занимает свое место.
Функциональность компонентов с вкладки QReport становится очевидной на практике. Аналогично можно сказать про полосы и их выравнивание в режиме конструктора.
Будет не лишним обратить внимание на пару примеров из папки:
“C:\Program Files\Borland\Delphi7\Demos\Quickrpt\”,которые устанавливаются вместе с Delphi.
Из событий QuickReport стоит отметить OnPreview и OnNeedData.
1-е можно использовать для вывода своего собственного окна просмотра вместо заданного по умолчанию.
2-е используется, когда источник данных не является базой данных VCL. Например, вы можете создать отчет для списка строк, массива или текстового файла [1].
Печать текста и графики
В случаях, когда необходимо выполнить вывод на печать текста, либо графики не из базы данных, следует использовать возможности, построенные на базе класса TPrinter.
Чтобы объект TPrinter стал доступен в проекте, необходимо добавить в раздел uses модуль Printers. Объект TPrinter не надо инициализировать. Достаточно только подключить модуль и объект становится доступным через переменную Printer, которая объявлена в данном модуле. Работа с объектом TPrinter базируется на его свойстве TCanvas. Поскольку данное свойство представляет собой графический контекст, то нужно быть готовым к тому, что вывод текста выполняется также в виде графики. В тоже время, свойство TCanvas инкапсулирует в себе низкоуровневые функции по работе с графическим контекстом, что значительно облегчает работу программиста.
Перечислим основные Свойства объекта TPrinter:
Aborted – переменная типа Boolean. Если она равна true, то пользователь прекратил вывод информации на принтер.
Canvas – объект типа TCanvas. Это холст, на который можно выводить информацию в графическом виде.
Copies – количество копий документа необходимых для печати.
Fonts – список шрифтов поддерживаемых принтером.
Handle – здесь храниться дескриптор контекста принтера. Через него можно воспользоваться напрямую функциями WinAPI.
Orientation – ориентация страницы. Это свойство может иметь одно из следующих значений: poPortrait – книжный, или poLandscape – альбомный.
PageHeight – высота страницы в пикселях.
PageWidth – ширина страницы в пикселях.
PageNumber – номер текущей печатаемой страницы.
PrinterIndex – число, которое указывает на номер активного принтера.
Printers – список типа TStrings установленных в системе принтеров.
Printing – если это свойство равно true, то принтер в данный момент печатает.
Title – заголовок или просто текстовое описание печатаемого документа. Этот заголовок будет отображаться во время печати в менеджере печати.
Методы объекта TPrinter:
Abort – прерывает текущую печать.
BeginDoc – начало печатаемого документа.
EndDoc – конец документа.
GetPrinter – получить индекс текущего принтера.
NewPage – новая страница документа.
Refresh – обновить информацию о шрифтах
В начале кода, выводящего на печать, будет разумно, а также профессионально, воспользоваться компонентом TPrintDialog. Для того, чтобы пользователь мог задать особенности печати. Это, как минимум, диапазон печатаемых страниц, количество копий и т.п.
Эта информация далее по коду будет доступна через такие свойства данного компонента, как FromPage, ToPage, Copies.
Настройка таких свойств печати, как ориентация бумаги или выбор принтера автоматически помещается компонентом TPrintDialog в объект TPrinter.
Возможно, программист захочет отойти от предлагаемых стандартных диалогов TPrintDialog, TPrinterSetupDialog, и реализовать свои, в каком-либо собственном стиле. В этом случае потребуется напрямую обращаться к свойствам Orientation, Printers, PrinterIndex и методам GetPrinter, SetPrinter объекта TPrinter. Если эта реализация окупается здравым смыслом – почему бы нет. Но при этом нужно быть готовым к дополнительным затратам разработки. И, конечно же, разработанный пользовательский стиль диалога печати должен отвечать некоторым стандартам, и быть понятным и удобным для пользователя.
Следующим шагом будет настройка нужного шрифта, например так: Printer.Canvas.Font := Memo1.Font;
И необходимо внести коррективу размера шрифта под разрешение контекста принтера, например так:
LineHeight:= Abs(
MulDiv(Printer.Canvas.Font.Size,
GetDeviceCaps(Printer.Handle, LOGPIXELSY), 72));
Рассмотрим эту формулу более подробно.
Переменная LineHeight будет хранить высоту строки уже на канве принтера. Функция WinAPI GetDeviceCaps ищет информацию об указанном устройстве. В нашем случае особый интерес представляет параметр LOGPIXELSY. Он возвращает число пикселей в логическом дюйме по высоте контекста. Свойство Font.Size по умолчанию ориентировано на разрешение равное 72. Поэтому необходимо выполнить формулу Font.Size * LOGPIXELSY / 72. На большинстве принтеров LOGPIXELSY равно 600. WinAPI функция MulDiv умножает два 32-разрядных значения и затем делит 64-битовый результат на третье 32-разрядное значение. Возвращаемое значение округлено вверх или вниз к самому близкому целому числу. Использование этой функции удобнее обычной арифметики тем, что функция кроме самого вычисления совмещает в себе округление.
К полученному результату добавляем 40 % на межстрочный интервал
Inc(LineHeight, (LineHeight*4) div 10);
Определение количества строк на странице.
LinesPerPage:= (Printer.PageHeight div LineHeight) ;
После этого можно приступать непосредственно к формированию задания на печать. Для этого вызывают метод
Printer.BeginDoc;
и в цикле начинают выполнять вывод строк. При этом нужно помнить, что при работе с контекстом принтера следует придерживаться графических функций.
Для вывода текста обычно используют Printer.Canvas.TextOut. Для вывода заголовков, либо колонтитулов, удобно воспользоваться WinAPI функцией DrawText, которая удобным образом центрирует текст на странице.
При выводе строк в цикле имеет смысл организовать переменную-счетчик, которая будет следить за достижением выведенного количества строк значения переменной LinesPerPage. И в этом случае, новая страница начинается при помощи метода Printer.NewPage.
Когда задание на печать сформировано, должен быть вызван метод Printer.EndDoc. И только после этого начнется непосредственная печать документа на принтере.
Замечание для тех случаев, когда понадобится воспользоваться функциями WinAPI напрямую, например для рисования, типа:
Printer.BeginDoc;
Rectangle(Printer.Canvas.Handle, 0,0,500,500);
Rectangle(Printer.Handle,500,50,700,800);
Printer.EndDoc;
то контекст канвы принтера одинаков и через
Printer.Canvas.Handle
Printer.Handle
Замечена разница:
Обращение к дескриптору 1-го типа за пределами BeginDoc, EndDoc, например:
memo1.Lines.Append(inttostr(Printer.Canvas.Handle));
поднимает исключение “raised exception class EPrinter with message ‘Printer is not currently printing”.
Вариант c дескриптором 2-го типа
memo1.Lines.Append(inttostr(Printer.Handle));
работает без исключения, и номер дескриптора возвращает правильный – такой же, как и внутри BeginDoc, EndDoc в процессе печати.
Однако вызов
Rectangle(Printer.Handle,500,50,700,800);
без входа в BeginDoc, EndDoc – печати конечно не делает. Происходит “мягкое” игнорирование без исключения.
Также, для печати текста без какого-либо форматирования, можно использовать код:
Var f:TextFile;
begin
AssignPrn(f);
Rewrite(f);
Writeln(f, ‘Hello world’);
CloseFile(f);
end;
В этом случае, также необходимо подключить модуль Printers. Поскольку в данном коде объект TPrinter используется неявным образом.
В статье рассмотрены основные приемы программирования печати. Выбор нужного способа за программистом, и зависит от конкретной ситуации.
Библиографическая ссылка
Бартосик Ф.М., Молдаванова И.Г., Мурых Е.Л., Авилова Е.К. ПЕЧАТЬ В DELPHI 7 // Международный журнал экспериментального образования. – 2015. – № 12-3. – С. 363-366;URL: https://expeducation.ru/ru/article/view?id=9127 (дата обращения: 17.08.2024).