СТАТЬЯ |
19.02.01
|
Деннис П. Батлер
Cтатья была опубликована на сайте www.olap.ru
Разработка и реализация отчетов для приложений обычно рассматривается как одна из многих связанных с разработкой задач. Кто захочет тратить много времени на форматирования, тестирования и работу с целым рядом отчетов, когда есть более интересные идеи, которые могут быть реализованы в продукте? Хотя это и не самая любимая часть процесса разработки приложения, однако часто критичным оказывается интерфейс между данными, загружаемыми приложением, и ее пользователем. Многоярусные, многошаговые, многоязычные приложения работающие под многочисленными операционными системами на разных континентах не выполнят свои задачи, если конечный пользователь, нажав кнопу "Print.." не удовлетворится видом отчета и выкинет его в мусорную корзину.
Одной из проблем генераторов отчетов является необходимость их установки конечными пользователями. Каждый, кто работал с приложениями, с большим количеством отчетов, может подтвердить, что как бы вы не форматировали ваш отчет, всегда найдется тот, кто скажет: "Конечно, это выглядит превосходно, ну а если я захочу сделать::.?" Не существует такого генератора отчета, который сможет сделать абсолютно все, что придет в голову конечному пользователю. Поэтому предпочтительным или даже необходимым как для конечного пользователя, так и для разработчика, перед тем как создавать отчеты, ознакомиться с основными принципами их создания. При этом придется потратить значительное время для того, чтобы понять какое из средств дает наибольшую функциональность и гибкость, соответствующую сложности и требованиям отчета.
В данной статье будут описаны некоторые опции, доступные разработчикам Delphi и C++Builder для создания отчетов в их приложениях.
Для этого в статье будут рассмотрены следующие средства для создания отчетов:
Конечно же, невозможно включить в небольшую исчерпывающую статью все, доступные сегодня разработчикам, средства создания отчетов. В данной статье в основном описаны генераторы Отчетов, входящие на сегодняшний день в сообщество Delphi и C++Builder. Автор использовал последние, к моменту написания статьи, версии средств создания отчетов. Использовались последние версии Delphi (5) и C++Builder (4/5)
Целью данной статьи является не только дать обзор доступных средств создания отчетов и их возможностей, но также помочь разработчикам правильно выбрать необходимое им средство создания отчетов.
Прочитав данную статью, разработчик сможет принять правильное решение о том, какое из средств является лучшим для конкретного проекта.
Как уже отмечалось, эта статья посвящена анализу средств генерации отчетов. Каждое из этих средств отличается своим способом дизайна, разработки и поставки отчетов с приложением. В этом разделе мы вкратце опишем их. Далее в статье мы более подробно остановимся на каждом из этих средств.
TPrinter
Объект TPrinter, включенный во все версии Delphi и C++Builder, является прямым интерфейсом между компьютером и печатающим устройством. Это объект, с помощью которого пользователь может сначала проконтролировать, что будет выведено в область (canvas) печати и затем отправить это на принтер. Для использования всех возможностей объекта достаточно лишь включить в разделы программы "uses" или "include" модуль printers. После этого объект TPrinter будет автоматически создаваться при запуске проекта. Пользователь сможет создавать запросы к нему с помощью функции 'Printer'.
**В прошлых версиях Delphi/C++Builder модуль printers использовал глобальную переменную 'Printer', к которой можно было обращаться, включив ее в программу. Однако часто данный модуль включался в программу, но ни разу не применялся в ней. Использование же вызова функции (возвращающей объект TPrinter) уменьшает потери такого рода в приложениях.
Объект TPrinter не требует никаких специальных условий для включения в окончательную версию продукта и никак не влияет на приложения, кроме как используя память при включении в программный код.
QuickReport
Закладка QuickReport на палитре компонентов Delphi или C++Builder содержит все компоненты, обеспечивающие поддержку QuickReport в приложениях.Данное средство для генерации отчетов является собственной компонентой VCL среды разработчика Delphi или C++Builder, так что как и для TPrinter не требуется соблюдения никаких дополнительных условий по использованию или инсталляции. Для использования QuickReports, компоненты просто перетаскиваются из палитры компонентов на форму и настраиваются для использования либо во время написания, либо во время выполнения программы.
Все три средства создания отчетов в своей основе аналогичны QuickReports, они являются VCL компонентами интегрированной среды разработчика. Для их использования также не требуются дополнительные требования по установке. Приобретаются они отдельно от Delphi или C++Builder. Ниже приведены web-страницы, где можно получить о них более подробную информацию:
Независимые генераторы отчетов непосредственно не связаны с языками программирования Delphi или C++Builder. Вместо этого, данные продукты являются отдельными и в них включается дизайнер отчетов и небольшой макроязык. Они имеют гораздо больше возможностей, но для использования требуют наличия ряда библиотек DLL и других файлов отчета. Seagate Crystal Reports представлен одной компонентой, представляющей интерфейс для взаимодействия с ядром генератора отчетов, в дополнение к прямым вызовам API генератора..
Как было сказано выше, объект TPrinter, включенный в Delphi и C++Builder, является основным средством для отправки информации непосредственно на принтер. Это объект с набором ключевых свойств и методов для выполнения этой задачи. Он имеет полностью невизуальный интерфейс и поэтому необходимо вручную программировать его функциональность.
Ниже приведен очень простой пример как можно использовать объект TPrinter для того, чтобы отправить текстовое сообщение на принтер.
procedure TfrmTPrint.btnSimpleTextClick(Sender: TObject); begin with Printer do // вызов функции Printer, возвращающей TPrinter begin BeginDoc; // Начать текущий процесс печати Canvas.TextOut(0, 120, edtSimpleText.Text); // Нарисовать канву (Canvas) в позиции 0,120 EndDoc; // Завершить ткущую процесс печати (начать печатать) showmessage('Text sent to printer.'); end; end;
код C++Builder показан ниже.
void __fastcall TfrmTPrint::btnSimpleTextClick(TObject *Sender) { Printer()->BeginDoc(); Printer()->Canvas->TextOut(0, 120, edtSimpleText->Text); Printer()->EndDoc(); MessageBox(NULL,"Text sent to printer.","Printing Completed", MB_OK); }
BeginDoc означает, что мы готовы отправить новую страницу на печать. ">" - Здесь мы вносим изменения в свойство Canvas объекта TPrinter, используя функцию TextOut. Данная функция определяет текст, который будет помещен в область Canvas и его положение в пикселях. Вызов EndDoc означает окончание работы печати и отправки результата на принтер. Для печати используются установленные по умолчанию шрифты. Их можно изменить в свойстве Font объекта Canvas.
Существует ряд других свойств и методов, позволяющих отправлять более сложные выходные данные на печать в TPrinter. Также существуют несколько стандартных свойств для контроля печати, таких как число копий, ориентация страницы, название задания печати, номер текущей страницы и т.д.
Так как контроль печати устанавливается на низшем уровне, другие простые операции, такие как создание новой страницы, также доступны пользователю. Например, если вы хотите распечатать таблицу, не поместившуюся на одной странице, вам надо будет в нужный момент создать новую страницу. Для этого необходимо использовать следующий код.
procedure TfrmTPrint.btnDBCustomersClick(Sender: TObject); var iYPos : integer; begin with Printer do begin BeginDoc; iYPos := 150; // Установить Y позицию для текста tblCustomer.Open; While not tblCustomer.EOF do begin // Вывести все компании из таблицы клиента Canvas.TextOut(0, iYPos, tblCustomer.FieldByName('Company').AsString); tblCustomer.Next; inc(iYPos, 150); // Контроль окончание текущей страницы if iYPos > PageHeight then begin iYPos := 150; NewPage; // Вызвать новую страницу end; end; EndDoc; showmessage('Customer information sent to printer.'); end; end;
..и код C++Builder.
void __fastcall TfrmTPrint::btnDBCustomersClick(TObject *Sender) { int iYPos; Printer()->BeginDoc(); iYPos = 150; tblCustomer->Open(); while(!tblCustomer->Eof) { Printer()->Canvas->TextOut(0, iYPos, tblCustomer->FieldByName("Company")->AsString); tblCustomer->Next(); iYPos = iYPos + 150; if (iYPos > Printer()->PageHeight) { iYPos = 150; Printer()->NewPage(); } } Printer()->EndDoc(); MessageBox(NULL,"Customer information sent to printer.","Printing Completed", MB_OK); }
Как выше отмечалось, в последних версиях Delphi и C++Builder была немного изменена реализация класса TPrinter. Теперь в модуль printers не входит глобальная переменная Printer. Это факт, а также наличие глобальной функции SetPrinter, позволяет теперь использовать несколько работающих независимо переменных. Благодаря этому пользователь имеет возможность, используя обращение к одному и тому же коду, устанавливать несколько принтеров с различными конфигурациями, легко переключаться между ними, не боясь потерять информацию.
В качестве примера приведем следующий Delphi код.
procedure TfrmTPrint.btnSwitchPrinterClick(Sender: TObject); var newPrinter, oldPrinter : TPrinter; bmInput : TBitmap; begin // Инициализация второй переменной принтера newPrinter := TPrinter.Create; newPrinter.Copies := 1; newPrinter.Orientation := poPortrait; bmInput := TBitmap.Create; try bmInput.LoadFromFile('C:\INPRISE.BMP'); // Установить текущий дескриптор принтера на исходный принтер // Напечатать две копии, одну для вымышленного клиента и другую для заполнения Printer.Copies := 2; Printer.Orientation := poLandscape; with Printer do begin BeginDoc; // Добавить некоторую информацию в отчет Canvas.Draw((PageWidth - bmInput.Width) div 2, 0, bmInput); Canvas.TextOut(0, 500, 'This report brought to you by Delphi 4!'); EndDoc; end; // Запомнить старые установки принтера в oldPrinter, назначить новое значение Printer // с помощью newPrinter oldPrinter := SetPrinter(newPrinter); try // Выбрать драйвер факс-принтера, который создаст факс-файл на жестком диске Printer.PrinterIndex := Printer.Printers.IndexOf('Print to Fax on PRINTFAX:'); with Printer do begin BeginDoc; Canvas.TextOut(0, 150, 'REPORT GIVEN TO CUSTOMER '+DateTimeToStr(Now)); EndDoc; // Отправить это по факсу используя драйвер факс-принтераend;
// Здесь код для запуска программы для отправки файла по факсу // ... // если FaxWasSentSuccessfully то begin SetPrinter(oldPrinter); // Вернуться к исходной конфигурации принтера // В этом месте мы можем в любой момент вернутся к интерфейсу факс-принтера с помощью // вызова SetPrinter. with Printer do begin BeginDoc; Canvas.TextOut(0, 150, 'FAX CONFIRMATION REPORT'); // Несколько строк для вывода на принтер результатов работы нашего фиктивного факса // .... // еще дейстует исходная конфигурация для печати EndDoc; end; end; finally // Здесь мы освободим (free) обьект newPrinter // Освободим обьект oldPrinter, ели мы не использовали SetPrinter для перехода к oldPrinter. newPrinter.Free; end; finally bmInput.Free; end; showmessage('Printed two reports, faxed report, and printed fax confirmation.'); end;
А также код C++Builder..
//---------------------------------------------------------------------------void __fastcall TfrmTPrint::btnSwitchPrinterClick(TObject *Sender) { TPrinter* newPrinter; TPrinter* oldPrinter; Graphics::TBitmap* bmInput; // Определим новый обьект принтера отдельно от исходной (default) функции Printer() newPrinter = new TPrinter; newPrinter->Copies = 1; newPrinter->Orientation = poLandscape; // Загрузим какой-нибуть график для нашего вывода bmInput = new Graphics::TBitmap; bmInput->LoadFromFile("C:\\INPRISE.BMP"); // Выведем первый отчет Printer()->Copies = 2; Printer()->Orientation = poLandscape; Printer()->BeginDoc(); Printer()->Canvas->Draw(200, 0, bmInput); Printer()->Canvas->TextOut(0, 500, "This report brought to you by C++Builder 4!"); Printer()->EndDoc(); // Переключимся на обьект факс-принтера, запомнив исходный обьект принтера в oldPrinter oldPrinter = SetPrinter(newPrinter); Printer()->PrinterIndex = Printer()->Printers->IndexOf("Print to Fax on PRINTFAX:"); Printer()->BeginDoc(); Printer()->Canvas->TextOut(0, 150, "REPORT GIVEN TO CUSTOMER "+DateTimeToStr(Now())); Printer()->EndDoc(); // Здесь размещается код для вызова программы для отправки факса // ... // если (FaxWasSentSuccessfully), то { // Возврат к исходному обьекту принтера SetPrinter(oldPrinter); Printer()->BeginDoc(); Printer()->Canvas->TextOut(0, 150, "FAX CONFIRMATION REPORT"); // Несколько строк для отправки результатов с помощью нашего фиктивного факса // .... // еще дейстует исходная конфигурация для печати. Printer()->EndDoc(); } // ~если (FaxWasSentSucessfully) // Здесь мы освободим обьект newPrinter // Освободим обьект oldPrinter, ели мы неиспользовали SetPrinter для перехода к oldPrinter. newPrinter->Free(); bmInput->Free(); MessageBox(NULL,"Printed two reports, faxed report, and printed fax confirmation.", "Printing Completed", MB_OK); } //---------------------------------------------------------------------------
Не надо путать глобальную функцию SetPrinter с методом SetPrinter объекта TPrinter, являющимся внутренним методом, который не может быть вызван напрямую.
Отметим еще несколько важных свойств объекта TPrinter.
Aborted - Показывает, что работа принтера была прервана методом Abort
Capabilities - Показывает возможности текущего принтера
Fonts - Список шрифтов, доступных для текущего принтера
Handle - Задает дескриптор (handle) для объекта print
PageNumber - Задает номер текущей страницы для печати
PrinterIndex - Задает текущий принтер из свойства Printers. Значение -1, соответствует выбору "принтера по умолчанию"
Printers - Список доступных в настоящий момент принтеров
Printing - Указывает на начало печати. Сообщение появляется после вызова процедуры BeginDoc, но до процедуры EndDoc, которая инициализирует работу принтера
Таким образом, обьект TPrinter предлагает простое и гибкое решение пользователям, которым необходим абсолютный контроль над информацией, посылаемой на принтер. Хотя все, что печатается должно быть определено в объекте Canvas с помощью соответствующего кода, нет никаких ограничений для пользователей, предпочитающих полный контроль над выводом. Для тех кому нужен контроль за простым или нестандартным выводом, обьект TPrinter предлагает простой способ для отправки на печать любых, созданных с помощью Canvas, выходных данных.
Набор компонентов QuickReports был доступен в различных версиях Delphi и C++ Builder, и имеет свою собственную закладку в палитре VCL. Кроме доступных в изчальной поставке IDE компонентов, пользователь также может приобрести расширенный набор компонентов QuickReports для создания отчетов новых типов с новыми возможностями экспорта.
В данной статье будут описаны только стандартные компоненты, так как они обычно чаще используются пользователями.
Основной особенностью QuickReports является то, что пользователь может поместить на форму компонент формата отчета (TQuickRep), добавить различные зоны (quickreport bands) , а также визуальные компоненты QuickReport для дизайна вашего отчета.
Имеются несколько типов зон (bands), которые могут быть использованы отдельно или в связке друг с другом для создания необходимого вам отчета. Также имеются несколько встроенных функций для проведения различных расчетов или сравнений при создании отчета. Созданный отчет можно предварительно посмотреть, распечатать или экспортировать в разных форматах.
Преимуществом в использовании интегрированного генераторов отчетов, такого как QuickReports, в сравнении с независимыми средствами, такими как Crystal Reports, является то, что пользователь имеет возможность четко контролировать размещение необходимой информации на экране дисплея.
Так как обьект написан на языке object Pascal, пользователь имеет превосходный доступ к средствам печати и, тем самым, много возможностей в управлении простыми или сложными отчетами. Основанный на Delphi или C++Builder компонент делает простым как изменение его возможностей, так и создание своих собственных средств написания отчетов, тогда как в Crystal Reports это невозможно.
Давайте рассмотрим простой пример quickreport, и как мы его отправим на печать. Данный отчет будет содержать список содержимого таблицы CUSTOMER базы данных DBDEMOS, включенную в демонстрационные примеры Delphi и C++Builder.
Ниже приведены объявления, определяющие данную форму.
type
TfrmTQReport = class(TForm)
QuickRep1: TQuickRep;
tblCustomer: TTable;
qrbDetailBand: TQRBand;
qrbPageFooter: TQRBand;
qrbHeader: TQRBand;
qrlCustList: TQRLabel;
qrlPage: TQRLabel;
qrlCustId: TQRLabel;
qrlCustName: TQRLabel;
qrlState: TQRLabel;
qrlCountry: TQRLabel;
qrsDate: TQRSysData;
qrsPage: TQRSysData;
qrdCustId: TQRDBText;
qrdCustName: TQRDBText;
qrdState: TQRDBText;
qrdCountry: TQRDBText;
private
{ Private declarations }
public
{ Public declarations }
end;
Заголовочный файл C++ Builder представлен ниже. Файл .cpp не содержит подробностей реализации.
//---------------------------------------------------------------------------
#ifndef prntqrH
#define prntqrH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Db.hpp>
#include <DBTables.hpp>
#include <ExtCtrls.hpp>
#include <Qrctrls.hpp>
#include <QuickRpt.hpp>
//---------------------------------------------------------------------------
class TfrmTQuickReport : public TForm
{
__published: // Компоненты, управляемые IDE
TQuickRep *QuickRep1;
TQRBand *qrbDetailBand;
TQRDBText *qrdCustId;
TQRDBText *qrdCustName;
TQRDBText *qrdState;
TQRDBText *qrdCountry;
TQRBand *qrbPageFooter;
TQRSysData *qrsPage;
TQRLabel *qrlPage;
TQRBand *qrbHeader;
TQRLabel *qrlCustList;
TQRSysData *qrsDate;
TQRLabel *qrlCustId;
TQRLabel *qrlCustName;
TQRLabel *qrlState;
TQRLabel *qrlCountry;
TTable *tblCustomer;
private: // Установки пользователя
public: // Установки пользователя
__fastcall TfrmTQuickReport(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TfrmTQuickReport *frmTQuickReport;
//---------------------------------------------------------------------------
#endif
Этот код сгенерирован помещением на форму компонента TQuickRep, далее на этот компонент помещается три компонента TQRBand, добавляется компонент TTable для источника данных, и в соответствующие зоны добавляются различные метки, системные переменные, и компоненты базы данных. TQuickRep был настроен так, чтобы он указывал на компонент TTаble в качестве источника данных, и компоненты базы данных были также связаны с этим TTable и сконфигурированы для тех полей, на которые они указывают.
Помещенный на форму компонент TQRBands использует свойство BandType для определения типа используемой зоны. В данном примере используются три типа зон: page header - верхний колонтитул, page footer - нижний колонтитул и detail. В разделе detail каждая запись из набора данных будет отделяться линией. Каждый компонент QuickReport, помещенная в соответствующую зону, может быть связан с различными наборами данных, что в свою очередь предоставляет возможность просматривать и связываться с другими таблицами или запросами.
Отчет можно предварительно просмотреть, щелкнув правой кнопкой мыши на TQuickRep и выбрав меню "Preview". Следует отметить, что при этом не учитывается код обработчика событий, добавленный в программу для взаимодействия с QuickReport-компонентами. С другой стороны, пользователь может использовать методы Preview, Print и ExportToFilter, включенные в объект TQuickRep для просмотра, печати и т.д. отчета во время работы готовой программы.
Следует подробно остановится на том, как процесс создания отчета взаимодействует с dataset, , являющимся источником данных. Тем более, что то же самое происходит и во многих других интегрированных средствах создания отчетов.
В процессе выполнения представленного выше отчета, будут последовательно считываться данные из TTable, так что в конце этой операции курсор будет находиться на последней записи таблицы. Этот факт необходимо учитывать, особенно, когда отчет разработан одновременно как для обработки, так и для вывода на экран монитора одинаковых наборов данных. При запуске отчета с визуальными средствами управления в режиме фонового процесса, обычно будут выводиться текущие записи, если конечно вы не отключили данные средства управления в программе. Особенно в ситуациях, когда в отчет вносятся многочисленные критерии сортировки или фильтрации, после завершения выполнения отчета параметры средств управления данными могут отображать сильно различающееся представление данных по сравнению с тем, что было перед запуском отчета. Чтобы избежать этого, считается правильным использовать различные наборы данных для компонентов отчета и для компонентов формы.
Для более сложных отчетов могут понадобиться функции общего итога или группирования для вывода результатов. Для этого в QuickReports имеются несколько методов. Ниже приведен пример создания более сложного отчета, включающий режим стягивания для перекрывающихся полей.
Данный отчет показывает как могут использоваться вместе зоны child и subdetail для обеспечения альтернативного вывода. В этом примере будет выводиться первая группа, состоящая из полей Company Name, Address, и City, а затем вторая - State, Country, Fax, и Date of Last Invoice. Такой способ позволяет уместить на одной странице большое количество полей. Для этого необходимо связать вместе все дочерние зоны (сhildbands) и определить подходящие зоны группирования для каждой из дочерних зон.
Зоны отчета SubDetail необходимы для вывода информации, которая может содержать отдельное от основных данных отчета подмножество данных. В приведенном примере мы выводим информацию из одной таблицы, поэтому используются одинаковые наборы данных. Однако в других приложениях с каждой зоной отчета можно связать отдельный набор данных для создания одного итогового отчета, выводящего множество разнообразных данных из разных таблиц.
QuickReports является составной частью Delphi, поэтому он предоставляет возможность изменять поля в процессе выполнения отчета для обеспечения альтернативного способа просмотра данных. Компонента, предоставляющая данные возможности, называется редактором выражений - дизайнером, позволяющим создавать отчеты, основанные на выражениях, уменьшая при этом необходимость непосредственного программирования на Delphi/C++Builder. Однако, в отдельных ситуациях, бывает необходимо, например, просто добавить в QuickReport компоненту TQRLabel и поменять ее заголовок (caption) в событии BeforePrint. Используя такие возможности Delphi/C++Builder, разработчик может создавать отчеты практически любого вида, тогда как редактор выражений не может предусмотреть все ситуации.
Следует отметить, что для QuickReports существует поддержка конечных пользователей, хотя такая поддержка и не встроена в QuickReports непосредственно. QuickReport Artist является независимым продуктом, представляющим из себя комбинацию возможностей создания отчетов QuickReports с удобным (как для конечных пользователей, так и для разработчиков) интерфейсом. Хотя описание его утилит и выходит за рамки данной статьи, отметим все же что для разработчиков QuickReports доступны дополнительные функциональные возможности.
QuickReports это хорошее решение для пользователей, желающих создавать простые и гибкие отчеты с минимальными затратами. Однако с усложнением отчетов простота разработки и удобства использования QuickReports стремительно уменьшаются. Отсутствие у данного дизайнера отчетов полной и полезной документации и файлов подсказки, к сожалению, могут сильно расстроить начинающих пользователей, желающих воспользоваться преимуществами современных достоинств продукта.
Хотя некоторую информацию и можно получить путем проб и ошибок, тем не менее для новичка QuickReports будет довольно сложно определить подходят ли данные компоненты в конкретном случае или правильно ли они используются. Тем не менее некоторую информацию о том, как использовать компоненты, можно получить на соответствующих веб-страницах. Однако, все же придется потратить значительное время, чтобы понять, как правильно их использовать.
В момент написания данной статьи появилась информация о выходе в ближайшее время новой 3.0.6 версии QuickReports для Delphi 5 и такой же версии для C++Builder 5.
ReportPrinter Pro
ReportPrinter Pro - это интересная комбинация концепций, присущих как TPrinter так и QuickReports. Его основная функциональность базируется на концепции создания отчетов с помощью программирования; компоненты используются для организации процесса кодирования, но затем их характеристики определяются с помощью Delphi кода. Поначалу все это выглядит очень сложно, но благодаря встроенному интерфейсу все становится более понятным. RPPro имеет несколько компонент, с помощью которых пользователь может вставлять в код свойства и события для формирования области вывода отчета. При возникновении события, пользователь может разместить необходимую информацию в печатаемую область. Далее, при завершении данного события, эта информация будет послана на печать. В дополнение к созданию отчетов на основе кодов появилась третья версия ReportPrinter Pro с визуальным построителем отчетов - Rave, позволяющим разработчикам и конечным пользователям визуально создавать отчеты, так же как и в Crystal Reports и в других аналогичных приложениях.
Наличие данной программы, полностью основанной на сочетании программирования отчетов с применением визуальных и гибких средств, , таких как Crystal Reports или QuickReports, предоставляет разработчикам полный комплект возможностей для создания простых, сложных или наисложнейших отчетов.
Давайте рассмотрим простой отчет, который распечатывает содержимое таблицы animals из базы DBDEMOS, инсталлированной вместе с Delphi/C++Builder.
В этом отчете мы создадим верхний и нижний колонтитул, а также область сетки , которая будет заполнена данными из таблицы. Для этого мы откроем таблицу и, перемещаясь по ней, заполним сетку нужной информацией. Ниже приведен код данного отчета.
procedure TfrmReportPrintPro.ReportSystem1Print(Sender: TObject); procedure SetupTabs; // Данная процедура задает заголовок и таблицу begin with Sender as TBaseReport do begin // Создать установки страницы для начала печати "Grid" и его содержания SetFont('Tahoma', 12); SetTopOfPage; Home; // Очистить прошлые установки таблицы ClearTabs; // Установка цвета, стиля, ширины и т.д. для заголовков колонок SetPen(clNavy, psSolid , 1, pmCopy); // Определение ширины и характеристик каждой колонки SetTab(0.5, pjCenter, 1.5, 0, BOXLINEALL, 0); SetTab(NA, pjCenter, 1.0, 0, BOXLINEALL, 0); SetTab(NA, pjCenter, 1.5, 0, BOXLINEALL, 0); SetTab(NA, pjCenter, 2.5, 0, BOXLINEALL, 0); // Нарисовать заголовки колонок и вывести туда текст Bold := True; Italic := True; // Установить более толстый бордюр и текст для "Name" Tab(-2, -2, -2, -2, NA); Print('Name'); // Установить более толстый бордюр и текст для "Size" Tab(NA, -2, -2, -2, NA); Print('Size'); Tab(NA, NA, -2, -2, NA); Print('Weight'); Tab(-2, -2, -2, -2, NA); Println('Area'); Bold := False; // Установить позицию, расположение, ширину, границы, окантовку, и процент затенения для // каждого элемента "tab" входящего в содержание "grid" ClearTabs; // Очистить сохраненные ранее установки SetPen(clNavy, psSolid, 1, pmCopy); SetTab(0.5, pjLeft, 1.5, 10, BOXLINEALL, 0); SetTab(NA, pjCenter, 1.0, 10, BOXLINEALL, 10); SetTab(NA, pjCenter, 1.5, 10, BOXLINEALL, 20); SetTab(NA, pjLeft, 2.5, 10, BOXLINEALL, 30); SetFont('Tahoma', 12); Underline := False; Bold := False; end; end; begin With Sender as TBaseReport do begin // Установить видимую область для тела отчета SectionTop := 1.0; SectionBottom := 10.5; SectionLeft := 0.5; SectionRight := 8.0; // Вызов локальной процедуры для установки верхнего колонтитула таблицы и структуры SetupTabs; // Перемещение по таблице "animals" с выводом информации tblAnimals.First; While not tblAnimals.EOF do begin Print(#9+tblAnimals.FieldByName('Name').AsString); Print(#9+tblAnimals.FieldByname('Size').AsString); Print(#9+tblAnimals.FieldByname('Weight').AsString); Println(#9+tblAnimals.FieldByName('Area').AsString); tblAnimals.Next; // Проверить конец страницы if YPos > SectionBottom then begin NewPage; SetupTabs; end; end; // Очистить установки, которые мы изменяли ClearTabs; end; end; procedure TfrmReportPrintPro.ReportSystem1PrintFooter(Sender: TObject); begin with Sender as TBaseReport do begin SectionBottom := 10.75; // Напечатать информацию нижнего колонтитула SetFont('Tahoma',8); PrintFooter('Page ' + IntToStr(CurrentPage),pjLeft); PrintFooter('Date '+DateTimeToStr(Now),pjRight); PrintFooter('ReportPrinter Pro 3.0', pjCenter); end; end; procedure TfrmReportPrintPro.ReportSystem1PrintHeader(Sender: TObject); begin with Sender as TBaseReport do begin // Установить видимую область в области отчета SectionTop := 0.5; SetFont('Tahoma', 14); Bold := True; Underline := True; PrintHeader('DBDemos Animal Listing', pjCenter); // Сброс (Reset) видимой области SectionTop := 1.0; end; end;..а здесь код C++Builder.
void TfrmReportPrinterPro::SetupTabs(TObject *Sender) { TBaseReport* CurrentReport; // Установить заголовок и таблицы для печати CurrentReport = dynamic_cast<TBaseReport *>(Sender); CurrentReport->SetFont("Tahoma", 12); CurrentReport->SetTopOfPage(); CurrentReport->Home(); // Установить синий цвет таблицы (в зависимости от затенение) CurrentReport->TabColor = clBlue; // Очистить последнии установки Tab CurrentReport->ClearTabs(); // Установить цвет, стиль, ширину и т.д. для заголовков колонок CurrentReport->SetPen(clNavy, psSolid , 1, pmCopy); // Определить ширину и характеристики для каждой колонки // SetTab : // NewPos : Позиция Tab // NewJustify : метод выравнивания // NewWidth : ширина Tab // NewMargin : расстояние между границами Tab и текстом // NewLines : Определить окантовку границ // NewShade : Определить затенение границ (в процентах) CurrentReport->SetTab(0.5, pjCenter, 1.5, 0, BOXLINEALL, 0); CurrentReport->SetTab(NA, pjCenter, 1.0, 0, BOXLINEALL, 0); CurrentReport->SetTab(NA, pjCenter, 1.5, 0, BOXLINEALL, 0); CurrentReport->SetTab(NA, pjCenter, 2.5, 0, BOXLINEALL, 0); // Нарисовать заголовки колонок и вывести туда текст CurrentReport->Bold = true; CurrentReport->Italic = true; // свойства Tab - также, как при вызове #9, допускающее переопределение // Установить более толстый бордюр и текст для "Name" // LeftWidth, RightWidth, TopWidth, BottomWidth : Перейти к следующему Tab и нарисовать//его // ShadeOverride : Может переопределять исходный способ затенения CurrentReport->Tab(-2, -2, -2, -2, NA); CurrentReport->Print("Name"); // Установить более толстый бордюр и текст для "Size" CurrentReport->Tab(NA, -2, -2, -2, NA); CurrentReport->Print("Size"); CurrentReport->Tab(NA, NA, -2, -2, NA); CurrentReport->Print("Weight"); CurrentReport->Tab(-2, -2, -2, -2, NA); CurrentReport->Println("Area"); CurrentReport->Bold = false; // Установить позицию, расположение, ширину, границы, окантовку, и процент затенения для // каждого элемента "tab" входящего в содержание "grid" CurrentReport->ClearTabs(); // Очистить сохраненные ранее установки CurrentReport->SetPen(clNavy, psSolid, 1, pmCopy); CurrentReport->SetTab(0.5, pjLeft, 1.5, 10, BOXLINEALL, 0); CurrentReport->SetTab(NA, pjCenter, 1.0, 10, BOXLINEALL, 10); CurrentReport->SetTab(NA, pjCenter, 1.5, 10, BOXLINEALL, 20); CurrentReport->SetTab(NA, pjLeft, 2.5, 10, BOXLINEALL, 30); CurrentReport->SetFont("Tahoma", 12); CurrentReport->Underline = false; CurrentReport->Bold = false; } //--------------------------------------------------------------------------- void __fastcall TfrmReportPrinterPro::ReportSystem1Print(TObject *Sender) { TBaseReport* CurrentReport = dynamic_cast<TBaseReport *>(Sender); // Установить видимую область тела отчета CurrentReport->SectionTop = 1.0; CurrentReport->SectionBottom = 10.5; CurrentReport->SectionLeft = 0.5; CurrentReport->SectionRight = 8.0; // Вызов локальной процедуры для установки верхнего колонтитула таблицы и структуры SetupTabs(CurrentReport); // Перемещение по таблице "animals" с выводом информации tblAnimals->First(); while (!tblAnimals->Eof) { CurrentReport->Print("\t"+tblAnimals->FieldByName("Name")->AsString); CurrentReport->Print("\t"+tblAnimals->FieldByName("Size")->AsString); CurrentReport->Print("\t"+tblAnimals->FieldByName("Weight")->AsString); CurrentReport->Println("\t"+tblAnimals->FieldByName("Area")->AsString); tblAnimals->Next(); // Контроль конца страницы if (CurrentReport->YPos > CurrentReport->SectionBottom) { CurrentReport->NewPage(); SetupTabs(CurrentReport); } } // Очистить установки, которые мы ранее изменили CurrentReport->ClearTabs(); } //--------------------------------------------------------------------------- void __fastcall TfrmReportPrinterPro::ReportSystem1PrintFooter(TObject *Sender) { TBaseReport* CurrentReport = dynamic_cast<TBaseReport *>(Sender); CurrentReport->SectionBottom = 10.75; // Напечатать информацию нижнего колонтитула CurrentReport->SetFont("Tahoma",8); CurrentReport->PrintFooter("Page " + IntToStr(CurrentReport->CurrentPage),pjLeft); CurrentReport->PrintFooter("Date "+DateTimeToStr(Now()),pjRight); CurrentReport->PrintFooter("ReportPrinter Pro 3.0", pjCenter); } //--------------------------------------------------------------------------- void __fastcall TfrmReportPrinterPro::ReportSystem1PrintHeader(TObject *Sender) { TBaseReport* CurrentReport = dynamic_cast<TBaseReport *>(Sender); // Установить видимую область в области отчета CurrentReport->SectionTop = 0.5; CurrentReport->SetFont("Tahoma", 14); CurrentReport->Bold = true; CurrentReport->Underline = true; CurrentReport->PrintHeader("DBDemos Animal Listing", pjCenter);
// Сброс (Reset) видимой области
CurrentReport->SectionTop = 1.0;
}
//---------------------------------------------------------------------------
void __fastcall TfrmReportPrinterPro::btnRunReportClick(TObject *Sender)
{
ReportSystem1->Execute();
}
//---------------------------------------------------------------------------
void __fastcall TfrmReportPrinterPro::btnRunRaveClick(TObject *Sender)
{
RaveProject1->Execute();
} //---------------------------------------------------------------------------
Как вы видели, мы использовали компоненту TReportSystem для взаимодействия с ядром генерации отчетов. Данная компонента представляет собой комбинацию четырех компонент, поставляемых с первой версией ReportPrinter. В этом примере мы так построили программу, чтобы информация верхнего колонтитула выводилась в событие OnPrintHeader, нижний колонтитул - в событие OnPrintFooter, а основная информация - в OnPrint. Можно изменить код так, чтобы вся информация выводилась только через OnPrint, но разделяя события, ReportPrinter Pro позволяет вам логически разделять код. Данный способ генерации отчета отличается от других способов, таких как QuickReports, тем, что мы можем вручную, с помощью кода, установить большую часть функциональных особенностей отчета.
Компонента TReportSystem содержит много полезных свойств и методов для создания отчетов. Ниже в примерах мы более подробно рассмотрим их.
Данная техника создания отчетов предоставляет больше возможностей, чем QuickReports или Crystal Reports, позволяя определять каждую индивидуальную характеристику отчета. Это оказывается особенно полезным, когда необходимо совершенно точно контролировать на экране монитора процесс печати.
Благодаря возможностям данного метода, пользователям нет необходимости применять избыточное кодирование через TPrinter.
ReportPrinter Pro имеет независимую утилиту для создания отчетов - RAVE. RAVE - это независимый продукт, связанный с ReportPrinter Pro, и предназначен для использования разработчиками и конечными пользователями при создании и поддержке отчетов.
С этой точки зрения, ReportPrinter Pro отличается от большинства других средств создания отчетов, за исключением Crystal Reports, который также предоставляет конечным пользователям возможность создавать и модифицировать отчеты. RAVE также позволяет объединять несколько отчетов в одном файле, или пересылать их в любые хранилища данных, включая базы данных.
Благодаря этой способности, конечный пользователь получает возможность доступа к различным отчетам и при необходимости их модификации.
RAVES является дизайнером отчетов, наподобие Crystal Reports. Запускается он отдельно и предоставляет весь стандартный набор возможностей, как, например, перетаскивание полей, средств управления, линий, и форм. Для пользователей Delphi отметим, что RAVES имеет аналогичный инспектор объектов и дерево просмотра объектов, так что он вполне можно использоваться в качестве средства дизайна. В отличие от таких корпоративных продуктов, как Crystal Reports, корпоративная версия RAVES не требует покупки отдельной лицензии для каждого конечного пользователя.
Ниже представлен рисунок простого отчета, созданного с помощью построителя отчетов RAVE.
Кроме этого, начинающие пользователи имеют возможность использовать для создания своих отчетов встроенный мастер отчетов. Опытные пользователи могут углубиться в подробности для создания сложных отчетов. При работе с RAVE нет необходимости использовать коды; для связи с RAVE файлами и для доступа к отчетам, созданным в нем , можно применять компоненту TRaveProject. RAVE файл можно загрузить в Delphi и запустить его выполнение непосредственно из приложения.
RaveProject1.LoadFromFile('C:\CUSTOMER.RAV');
или
RaveProject1->LoadFromFile("C:\CUSTOMER.RAV");
Таким образом, основанное на программировании средство создания отчетов ReportPrinter Pro в комбинации с визуальным дизайнером RAVE представляют собой мощную утилиту, удовлетворяющую большинству потребностей при создании отчетов. Создание отчетов на программном уровне, как отмечалось выше, позволяет сконструировать фактически любой отчет. Среда RAVE использует знакомый интерфейс разработки отчетов. Пожалуй, единственным минусом ReportPrinter Pro является его сложность. Программное создание отчета представляет собой хотя и очень гибкое средство, но все же оно сложнее, чем простое перетаскивание объектов, как это делается в Ace Reporter или QuickReports. Хотя RAVE и позволяет использовать такие методы, но все же для конечных пользователей требуется некая предварительная тренировка.
Резюмируя все сказанное выше, можно отметить, что ReportPrinter Pro предлагает отличное решение для создания как простых, так и сложных отчетов.
Ace Reporter
Ace Reporter - еще одно многоцелевое средство создания отчетов для среды Delphi. Аналогично QuickReports он имеет компоненты, позволяющие разработчикам контролировать размещение отчета и определять взаимодействие с базой данных для формирования необходимого вывода данных. В отличие от ReportPrinter Pro он не основан на работе с кодом и имеет множество возможностей, позволяющих минимизировать такую работу. Ace Reporter имеет много простых отчетов, которые могут быть использованы разработчиками в качестве шаблонов для создания своих отчетов. Интерфейс Ace Reporter отличается от интерфейсов других средств, описанных в данной статье, благодаря встроенным в разработчик отчетов ряда настроек. В связи с этим значительно упрощается процесс создания и генерации отчетов. В отличие от других разработчиков отчетов, здесь не уделяется много внимания таким этапам как подключение компонент, организации их связи. Аналогично QuickReports, Ace Reporter также использует для доступа к данным средства управления баз данных Delphi/C++Builder. Благодаря этому не требуется дополнительного переопределения кодов при представлении локальных таблиц или SQL баз данных. Рассмотрим для начала простой пример отчета Ace Reporter.
Рисунок демонстрирует простой отчет, показывающий информацию клиента из базы с алиасом DBDEMOS, инсталлированную вместе с Delphi и C++Builder. Данный интерфейс отчета отличается от интерфейсов других средств генерации отчетов Delphi/C++Builder наличием средств, доступных во время разработки(design-time capabilities). Аналогично QuickReports, в форму помещается шаблон отчета, компонент TSctReport, создающий границы отчета. Данный компонент создает исходный отчет с набором уже заполненных по умолчанию зон. Кроме этого в шаблон включены несколько кнопок, создающих интерфейс для подключения к отчету дополнительной функциональности. Единственными компонентами, помещаемыми на отчет из палитры компонентов, являются средства управления, непосредственно не работающие с данными. . Это отличается от стиля QuickReports,, где все помещаемое на шаблон отчета необходимо конфигурировать вручную. Благодаря этому интерфейс становится более прозрачным и простым в использовании. Кроме того, палитра компонент не загружена большим количеством компонент, что может запутать пользователя, как это происходит в QuickReports.
Для запуска показанного выше отчета требуется лишь следующее.
AceRptSimple.Run;
Или для C++Builder
AceRptSimple->Run();
При этом будет запущен отчет в диалоговом окне.
Разработчик имеет возможности вносить множественные изменения в исходное размещение отчета, так же как это было возможно в других средствах генерации отчетов. Цвет, шрифты, различные установки могут быть изменены либо в зоне, либо на уровне настроек. Функциональность данного шаблона обеспечивается благодаря наличию встроенных кнопок, предоставляющих интерфейс к более сложным аспектам создания отчета. Опишем данные кнопки.
Используя возможности Ace Reporter, разработчик может создавать разнообразные сложные отчеты с более динамичным содержанием, чем в стандартных отчетах.
Рассмотрим теперь более сложный пример отчета и проанализируем некоторые из многих современных возможностей Ace Reporter.
Данный отчет показывает определенное в нем отношение "master-detail".
Важно отметить, что переменные выражений будут использоваться для определения количества дней, прошедших после последнего инвойса клиента. Для этого необходимо иметь возможность создавать в базе данных вычисляемое поле для получения данной информации, причем оно будет использоваться в отчете. Ниже приведен код, который позволяет это делать.
// Следующий код сохраняет правильное значение переменной evDaysPastInvoice procedure TfrmAceReporter.evDaysPastInvoiceGetData(oVar: TSctVar); begin // Проверьте, что дата инвойсв - меньше чем дата поставки if evCustomerLastInvoice.AsDateTime < evOrderShipDate.AsDateTime then oVar.AsString := IntToStr(Trunc(evOrderShipDate.AsDateTime - evCustomerLastInvoice.AsDateTime))+' days past last invoice.' else oVar.AsString := ''; end; // Здесь показано как переменные выражения могут быть использованы при расчете других //переменных выражения procedure TfrmAceReporter.evCustomerLastInvoiceGetData(oVar: TSctVar); begin oVar.AsDateTime := tblCustomer.FieldByName('LastInvoiceDate').AsDateTime; end; procedure TfrmAceReporter.evOrderShipDateGetData(oVar: TSctVar); begin oVar.AsDateTime := tblOrders.FieldByName('ShipDate').AsDateTime; end;
При использовании Ace Reporter совместно с программированием в среде Delphi, следует обратить внимание на несколько пунктов. Когда средства управления базой данных Ace помещаются на зоны, создаются переменные, ссылающиеся на информацию, которая должна быть выведена на печать. Это происходит потому, что ядро генератора Ace Reporter использует свой собственный метод перебора данных, и в процессе выполнения некоторых событий (например ..BeforePrint или ..AfterPrint) используемый источник данных может находиться в местах, отличных от того что ожидается событием во время печати. Однако, для событий GetData, источник база данных будет находиться там, где она должен быть, поэтому параметры выражения могут быть заданы в событиях OnGetData. Переменные, включенные в Ace Reporter, используются для создания связи с тем, что будет напечатано и они должны применяться при создании дополнительных расчетов в коде Delphi. Для каждого доступного поля создается компонента TSctDBVar или TSctVarLabel. Данные компоненты можно просматривать в любой момент создания отчета с помощью Data Control Center.
TSctVarLabel также можно использовать для создания обычных или специфических меток. В этой ситуации компонента может использоваться для вывода на экран информации, не содержащей конкретные данные. Полезным свойством компоненты является наличие ряда форматирующих установок. Таким образом, например, вставляя величину с плавающей точкой в поле currency вы можете отформатировать ее с помощью данной компоненты вместо написания программного кода. Форматируя данные вне выражения, вы упрощаете процесс модификации отчетов, использующих события.
Другое понятие, используемое Ace Reporter, это уровень коррекции. Каждая переменная имеет уровень коррекции, взаимодействующий с разделом отчета, где она используется для вывода следующего значения. Это полезно, когда вы выполняете некоторую "закулисную работу" с переменной. В основном вы просто должны быть уверены, что при тех манипуляциях, которые вы собираетесь применить в процессе работы отчета, переменная будет изменяться. В приведенном выше примере, переменные выражения имеют свои установки уровня коррекции, определяющие когда необходимо изменять значения переменных выражения. Так компонент evCustomerLastInvoice имеет уровень коррекции, связанный с зоной таблицы Customer, а компонента evOrderShipDate имеет уровень коррекции, связанный с зоной таблицы Orders. Компонента рассчитанных выражений evDayspastInvoice также имеет уровень коррекции, связанный с зоной таблицы Orders, так как ей необходимо изменять свои значения вместе с изменениями в каждой строчке отчета, показывающей информацию из таблицы Orders.
Еще одна полезная утилита, включенная в Ace Reporter, это автоматическое обновление. Она используется при переводе отчетов из старых в новые версии Ace Reporter. Хотя может и не быть каких-то различий в кодах между версиями, данная утилита используется, чтобы проконтролировать все ситуации, которые могут возникнуть при переходе к более высокой версии. Она проверит PAS и DFM файлы на наличие параметров, требующих изменения, и автоматически обновит их. Данная утилита очень полезна, особенно в сравнении с Crystal Reports, где новые компоненты, созданные в версии 6.0, по существу полностью отбрасывают структуру своего предшественника. Такие "впередсмотрящие" характеристики как эта являются неоценимыми для разработчиков.
На первый взгляд может показаться, что в палитре компонентов отсутствует много необходимых вещей, или возможности Ace Reporter сильно ограничены, так как здесь не требуется такого количества ручных установок, как в других средствах создания отчетов. Однако, я обнаружил, что данный метод на самом деле предоставляет высоко организованную и структурированную основу для создания отчета, и я также хочу оценить его простоту по сравнению с другими методами генерации отчетов. Хотя контроль происходит все еще на уровне зон и средств управления, но реализация и взаимодействие производится самим средством. Тем не менее, есть некоторые соображения, которые необходимо учесть при его использовании. Прежде всего, Ace Reporter в настоящий момент имеет возможность экспорта лишь в RTF формат. Это хуже, чем в других средствах создания отчетов, имеющих большой список форматов экспорта. Кроме того, такая среда как Crystal содержит мастера с большим количеством усложненных элементов расположения и форматирования, что значительно упрощает процесс создания отчета. Например, в Crystal Reports очень просто создаются матричные отчеты (Cross-tab), тогда как в данном методе это потребует значительно большей работы.
Суммируя можно сказать, что Ace Reporter это очень хорошее средство, включающее многолетний опыт Delphi/C++Builder. За исключением нескольких нюансов, упомянутых раньше, это мощное средство, которое можно быстро изучить и начать применять. К моменту написания данной статьи последней версией Ace Reporter для Delphi и C++Builder 5 была версия 1.24.
Crystal Reports
Crystal Reports представляет собой законченный, независимый продукт для создания отчетов, который широко используется разработчиками Visual Basic и Delphi. Это связано с тем, что он является мощным, разносторонним, проверенным и постоянно обновляющимся продуктом. Данное средство использует визуальную, контролируемую на уровне отдельных зон отчета (band-driven) среду вместе с компактным языком программирования и библиотекой функций для создания отчетов. Сами отчеты сохраняются как файлы Crystal Report (расширение .RPT). Кроме этого, разработчик должен распространять отчеты совместно с некоторыми библиотеками DLL, позволяющими использовать отчет на каждой клиентской машине.
Преимущество Crystal Reports заключается в том, что вы используете проверенный, надежный продукт компании, имеющей большое количество пользователей в различных программных сообществах. Это, в принципе, гарантирует поддержку и обновление продукта в будущем, тогда как компании, производящие средства создания отчетов только на базе "Delphi/C++Builderonly" этого не делают. Кроме этого, Crystal Reports имеет разнообразные опции экспорта, позволяющие взаимодействовать с Delphi через компоненту Tcrpe. Теоретически, иметь отдельный продукт для отчета дает некоторым пользователям возможность создавать в приложениях свои собственные отчеты, но в большинстве случаев, без предварительной тренировки, сделать это обычным пользователям бывает довольно сложно.
Есть несколько минусов в использовании Crystal Reports. Как было сказано выше, при установке на клиентских машинах вашего Delphi/C++Builder приложения, создающего отчеты, вам также потребуется установка некоторых библиотек DLL. В настоящее время для этого уже требуется свыше 8 MB дисковой памяти для каждого клиента. Размер файла CRPE32.DLL (главная библиотека отчетов) вырос с 1.4 MB для 16-битной среды до 5.3 MB в последних версиях. Вместе с DLL экспорта и DLL баз данных они занимают значительное дисковое пространство при инсталляции. Каждый раз, когда выходит новая версия продукта, разработчик должен решать, обновлять ли (а вероятнее всего уничтожать) отчеты, созданные в предыдущей версии. С момента выхода Delphi 1 были выпущены 4.0, 4.5, 5.0, 6.0, и 7.0 версии Crystal Reports. Последняя версия (8.0) пока не содержит новую версию его компоненты VCL, хотя она вероятно скоро появится. Я попытался скомпилировать приложение, созданное в версии 4.0, через все последующие до версии 7.0 и каждый раз как я это делал, возникали вопросы. Некоторые вопросы были простыми, а некоторые - сложными. Хотя Seagate обычно быстро реагирует на возникающие проблемы и предлагает на своей web-странице последние коррекции (patch), все же часто возникают ситуации, когда при переходе на новую версию приходится изменять форматирование существующего отчета, изменять его характеристики или даже удалять прежде доступные опции. Прежде чем переходить к Crystal Reports, надо обязательно учесть наличие таких проблем.
Crystal Reports существует уже много лет, начиная с первой 16-битной среды разработки отчетов для Windows 3.x. В те далекие дни необходимо было использовать прямые API запросы для генерации и распечатки отчетов, созданных в среде Crystal. Сегодня пользователи создают отчеты в среде Crystal Reports и используют компоненту Tcrpe для связи с ними из Delphi/C++Builder. Сама компонента Tcrpe также претерпела значительные изменения и была существенно модифицирована в Crystal 6.0. Данная компонента определяет какой именно файл отчета (.RPT) будет выведен на печать и позволяет пользователю манипулировать разными данными и аспектами, связанными с форматированием отчета.
После того как мы вкратце ознакомились с историей Crystal Reports и с существующими проблемами, давайте рассмотрим среду Crystal 7. Данная версия будет использоваться во всех примерах.
Этот первый пример созданного отчета. В данном отчете мы с помощью визуального эксперта (Crystal visual linking expert) связали таблицы customer.dbf и order.db и установили необходимые нам поля в зонах отчета, показанных выше. Мы также вставили в отчет (выберите Insert Group из меню) групповую зону(group band) для того, чтобы при изменении имени заказчика создавался новый раздел. В раздел detail были добавлены поля из таблицы. Ну и, наконец, в нижний колонтитул групп были добавлены поля total для CustomerName и для всего отчета. Отчет был сохранен с именем SIMPLE.RPT.
Очень важным отличием между Crystal Reports и собственными средствами создания отчетов Delphi является метод взаимодействия Crystal с данными. Как уже отмечалось выше, большинство интегрированных средств создания отчетов используют прямую связь с файлами данных. При этом они должны найти в файле необходимые для отчета данные, и затем применить критерии сортировки, фильтрации и т.д.. Из-за этого процесс создания отчета может неблагоприятно повлиять на визуальные компоненты средств управления, использующие тот же файл данных.
Crystal создает внутреннюю, хранящуюся в оперативной памяти таблицу, состоящую из выбранных для отчета таблиц и полей. После этого к данной таблице применяются все необходимые критерии сортировки , фильтрации и т.д. . Так как данный процесс является внутренним для Crystal и не требует участия пользователя, он значительно ускоряет вывод и упрощает ввод изменений без использования каких либо данных внутри приложения. Например, в QuickReports отчет будет выводить данные в зависимости от выбранного индекса для таблицы. А из-за того, что зоны групп используются без сортировки по типу групп, может быть создан бесполезный отчет, в котором одни и те же клиенты будут присутствовать в различных группах. В Crystal сортировка информации происходит автоматически, так что установка зон группы на "CustomerName" приведет автоматически к правильной сортировке данных. Это свойство Crystal Reports значительно упрощает создание сложных, но гибких отчетов. При этом пользователю не надо изменять индекс или порядок записей в базе.
Теперь, после того как мы создали наш простой отчет, рассмотрим как можно связаться с ним через код Delphi/C++Builder.
procedure TfrmCrystal7.btnSimpleCrystalClick(Sender: TObject); begin with Crpe1 do begin // Предполагается, что отчет находится в той же директории, что и приложение ReportName := ExtractFilePath(Application.ExeName)+'\SIMPLE.RPT'; Output := toWindow; Execute; end; end;
Все что мы сделали, это выбрали отчет, установили вывод на экран монитора и запустили выполнение отчета.
Существуют много способов подготовки отчета как в среде Crystal, так и с помощью мастеров создания отчета, предназначенных для помощи пользователю в выполнении данной задачи. С их помощью можно создавать большое количество разнообразных отчетов. Для исчерпывающего анализа среды Crystal Reports потребуется отдельная статья. Здесь мы этого делать не будем, а остановимся лишь на использовании компоненты Delphi/C++Builder Tcrpe для генерации отчетов. Отметим лишь, что Crystal Reports позволяет создавать разнообразные типы отчетов, удовлетворяющие всем потребностям, которые могут возникнуть в приложениях.
Теперь давайте более подробно изучим компоненту TСrpe. Ранее отмечалось, что в шестой версии Crystal она была существенно изменена, получив более профессиональную и логическую основу в сравнении с ее прошлыми версиями. Не смотря на то, что эти изменения и требуют значительных усилий при переносе отчета из старых версий Crystal в новые, идущие вперед разработчики получили более понятную и полезную компоненту. Следующий пример демонстрирует как применять наиболее часто используемые свойства компоненты. В начале рассмотрим форму, создающую данный код, а затем непосредственно сам код.
Данная экранная форма предоставляет некоторые опции пользователю при нажатии на кнопку "Print With Options". Код представлен ниже.
procedure TfrmCrystal7.btnPrintOptionsClick(Sender: TObject); begin Crpe1.ReportName := ExtractFilePath(Application.ExeName)+'\SIMPLE.RPT'; // Следующие очистки опций не обязательны если запускается только один отчет // Если у вас несколько отчетов, использующих одну и ту же компоненту // TCrpe, то в первую очередь лучше очистить все опции для недопущения // ошибки переполнения формулы Crpe1.Selection.Formula.Clear; // Очистить предыдущие критерии отбора Crpe1.Formulas.Formula.Clear; // Очистить предыдущую формулу Crpe1.Formulas.Clear; // Очистить имя предыдущей формулы Crpe1.SortFields.Clear; // Очистить поля сортировки // Добавьте формулу критерия выбора в отчет (не забудьте "and" aв конце первой линии) if cbCustomer.Text <> 'All Customers' then Crpe1.Selection.Formula.Add('{Customer.Company} = "'+cbCustomer.Text+'" and '); Crpe1.Selection.Formula.Add('{Orders.OrderNo} > '+IntToStr(seOrderNo.Value)); // Добавить формулу в отчет if edtPrintedBy.Text <> '' then begin Crpe1.Formulas.Add('fmlaPrintedBy'); Crpe1.Formulas.Formula.Add('"'+edtPrintedBy.Text+'"'); end; if edtComment.Text <> '' then begin Crpe1.Formulas.Add('fmlaComment'); Crpe1.Formulas.Formula.Add('"'+edtComment.Text+'"'); end; // Определить порядок сортировки Crpe1.SortFields.Add(0); case rgSort.ItemIndex of 0 : Crpe1.SortFields.Field := '{Orders.OrderNo}'; 1 : Crpe1.SortFields.Field := '{Orders.AmountPaid}'; 2 : Crpe1.SortFields.Field := '{Orders.ShipVIA}'; end; if cbSortAscending.Checked then Crpe1.SortFields.Direction := sdAscending else Crpe1.SortFields.Direction := sdDescending; // Определите куда выводить отчет case rgDestination.ItemIndex of 0 : Crpe1.Output := toWindow; 1 : Crpe1.Output := toPrinter; else // опция экспорта в файл begin Crpe1.Output := toExport; if rgDestination.ItemIndex = 2 then begin Crpe1.Export.FileType := Excel5; dlgSave.FilterIndex := 1; end else begin Crpe1.Export.FileType := HTML32std; dlgSave.FilterIndex := 2; end; // Получить имя файла if not dlgSave.Execute then exit; // Удалить если уже существует if FileExists(dlgSave.FileName) then DeleteFile(dlgSave.FileName); Crpe1.Export.FileName := dlgSave.FileName; end; end; // Запустить отчет Crpe1.Execute; end;
В данном примере мы увидели, как работают следующие свойства:
Selection - Используется для ограничения отчета по одному или нескольким величинам. Это свойство полностью соответствует выбору "Report", "Edit Selection Formula", "Record" из главного меню Crystal Report. Пользователь может получить текущие установки в отчете из Delphi с помощью вызова Crpe1.Selection.Retrieve или из кода с помощью Crpe1->Selection->Retrieve(), или двигаться дальше и вставить новые критерии отбора поверх старых. Необходимо отметить важную деталь дизайна. Для ввода в формулу отбора нескольких строк необходимо использовать операторы между отдельными критериями. В приведенном примере мы добавили оператор "and" в конце первого критерия.
GroupSelection -Данное свойство работает также, как и Selection. Оно позволяет задавать критерии отбора для целой группы. Например, ее можно использовать, чтобы ограничить отчет показом лишь тех клиентов, чей суммарный AmountPaid превышает определенное количество долларов.
Formulas - Используется для доступа из Delphi/C++Builder к полю формул Crystal Report. Это очень мощное свойство. Так как группировки могут производиться по формуле, данное свойство позволяет разработчикам легко управлять посредством программного кода типом группировки отчета.
SortFields - Используется для определения направления сортировки (сортировка в алфавитном и в обратном порядке).
Output - Используется для взаимодействия со свойством Export, для выбора места назначения отчета. Если для этого используется toExport, то свойство Export должно быть заполнено определенной информацией. В более сложных реализациях это свойство используется для пересылки отчета непосредственно по электронной почте, или в Word for Windows. Имеется еще много разных возможностей.
Отмеченные здесь свойства являются основными методами манипуляции данными, выводящимися в отчете. Компонента Tсrpe имеет также много других свойств изменения аспектов отчета, таких как установка полей страницы, количество копий и т.д. Поняв суть описанных здесь свойств, вы сможете начать создавать полезные, гибкие отчеты с минимумом усилий.
Таким образом, Crystal Reports 7/8 предоставляет пользователям великолепный метод для быстрого создания профессиональных отчетов. Его интерфейс прост в использовании, взаимодействие компонентов с отчетом более простое, чем в прошлых версиях и весь пакет создания отчетов весьма надежен и имеет хорошую поддержку.
Хотели бы вы и ваши пользователи найти более завершенный продукт? Даже и не пытайтесь.
Заключение
Целью данной статьи было не только простое описание доступных разработчикам разных средств генерации отчетов. Каждый из рассмотренных выше средств генерации отчетов имеет различные целевые группы пользователей и разработчиков, и окончательные цели, и это отражается в том, что каждый из них предлагает. Нет и никогда не будет абсолютно идеального, подходящего под все ситуации средства генерации отчетов.
В заключении приведем все, представленные в статье, средства с их сильными и слабыми сторонами.
TPrinter
J Простой и быстрый интерфейс принтера
J Всегда поддерживаемая часть Delphi/C++Builder
L Неудобен для сложных реализаций
QuickReports
J Встроенный - не требует дополнительных финансовых затрат для использования
J Визуальное band driven средство создания отчетов для быстрых и легких реализаций
J Встроенные в Delphi - не требует дополнительных библиотек
L Отсутствие полной документации усложняет его изучение
L Сложно создавать нестандартные отчеты
ReportPrinter Pro
J Визуальное band-driven- средство создания отчетов для быстрых и легких реализаций
(RAVE)
J Низкоуровневый контроль области печати (canvas) в комбинации с функциями для создания фактически любого типа вывода
J Исконно Delphi - Не требует дополнительных библиотек
L Создание отчета на уровне кодов. Требует знания многих функций и методологий
L Приобретается отдельно от Delphi/C++Builder
AceReporter
J Визуальное band-driven- средство создания отчетов для быстрых и легких реализаций
J Исконно Delphi - Не требует дополнительных библиотек
J Полная документация и примеры для создания разнообразных отчетов, поддержка "newsgroup"
J Удобное автоматическое преобразование кода при переходе на новые версии Ас
L Ограниченные возможности экспорта
L Приобретается отдельно от Delphi/C++Builder
Crystal Reports
J Визуальное band-driven- средство создания отчетов для быстрых и легких реализаций
J Самое крупное, из всех представленных здесь, средств создания отчетов
J Серьезное средство для опытных пользователей и разработчиков.
L Большое количество и большие размеры файлов необходимых при распространении отчетов
L Новые версии продукта и компонент часто несовместимы со старыми версиями
L Приобретается отдельно от Delphi/C++Builder
В зависимости от потребностей приложения, следует выбрать подходящее средство, обеспечивающее наилучшее соотношение функциональность/цена. Существуют еще много других средств создания отчетов, не вошедших в данную статью, которые также могут войти в одну из этих категорий, или даже могут перекрыть некоторые сильные или слабые стороны описанных средств. То, что они не представлены в статье не означает, что они чем-то хуже. Просто они имеют свойства и возможности, большинство из которых были описаны выше.
По моему мнению, фраза "Это грязная работа, но кто-то должен ее делать" слишком часто применялась к генерации отчетов. Разработчики, вооруженные подходящим средством генерации отчета, смогут отличить удачные приложения от неудачных, не говоря уже о возможности быстро разрабатывать продуктивные решения и, что главное, в срок. Данная статья позволит разработчику сделать правильный выбор необходимого для работы средства генерации отчетов.
Обсудить на форуме Seagate
Отправить ссылку на страницу по e-mail
Interface Ltd.Отправить E-Mail http://www.interface.ru |
|
Ваши замечания и предложения отправляйте автору По техническим вопросам обращайтесь к вебмастеру Документ опубликован: 19.02.01 |