Сергей Маклаков, Наталия Елманова.
В данной статье будет рассмотрена архитектура доступа к данным, функции API и способы включения отчетов Crystal Reports в приложения Borland Delphi 3.0 и Borland C++Builder 1.0/3.0.
Crystal Reports состоит из следующих основных компонентов:
Report Designer (файл CRW.EXE для 16 - разрядной версии и CRW32.EXE для 32- разрядной) - основной модуль, который позволяет разрабатывать отчеты и открывать *.rpt -файлы. Прочие компоненты (перечисленные ниже) играют вспомогательную роль.
Query Designer (CQW.DLL /CQW32.DLL) - инструмент для создания SQL- запросов (описан в третьей статье серии).
Data Dictionary (CDW. EXE / CDW.EXE) - словарь типовых решений для быстрой разработки отчетов. Словари хранятся в файлах *.DC5. Работа со словарями Crystal описана во второй статье серии.
Report Engine (CRPE.DLL / CRPE32.DLL) - API, дающий возможность разработчикам интегрировать отчеты в их собственные приложения. Создав отчет в Report Designer, можно просматривать его в приложениях, используя Report Engine. С помощью Report Engine можно во время выполнения устанавливать условия группировки данных, стили графиков, местоположение БД и многое другое.
Прямой доступ реализован для большинства форматов персональных БД (dBASE, FoxPro, Clipper, Btrieve, Microsoft Access и др.) и некоторых реляционных СУБД (Oracle 7, Microsoft SQL Server 6.x, Sybase System 10/11). Другими словами Crystal имеет встроенные возможности доступа к указанным источникам. Возможность прямого доступа появляется при инсталляции Crystal Reports. Прямой доступ имеет три уровня:
Доступ через ODBC (Open DataBase Connectivity - стандарт, позволяющий приложению иметь доступ к различным источникам данных) имеет пять уровней:
Все пять уровней используют для взаимодействия язык SQL
Модуль Crystal Reports Print Engine API предназначен для доступа к отчетам из приложений Windows. Доступ реализован через вызовы функций CRPE.DLL / CRPE32.DLL.
Первый шаг к использованию функций - их объявление. Функции могут быть объявлены как глобально, так и локально внутри использующей их секции кода. Каждая функция может быть объявлена отдельно, но имеется и возможность объявления всех функций сразу. Например, функция PEStartPrintJob может быть объявлена в Visual Basic как: Declare Function PEStartPrintJob Lib "CRPE.DLL" (ByVal printJob As Integer, ByVal waitUntilDone As Integer) As Integer
Для объявления всех функций сразу необходимо воспользоваться файлами заголовков, входящих в состав Crystal Reports. Например, для Visual Basic имя такого файла - GLOBAL.BAS, для С - CRPE.H.
После объявления функций для начала работы с отчетом необходимо вызвать функцию PEOpenEngine, которая возвращает значение TRUE (1), если вызов прошел успешно, либо FALSE(0), если CRPE.DLL / CRPE32.DLL загрузить не удалось. Функция PEOpenEngine не имеет параметров и служит только для обработки в программном коде факта успешного подключения Print Engine.
Для печати отчета используется функция PEPrintReport. Синтаксис функции приведен ниже: PEPrintReport("reportName", toPrinter, toWindow, "windowTitle", leftCoordinate, topCoordinate, windowWidth, windowHeight, windowStyle, parentWindow)
где:
Функции Report Engine позволяют не только просматривать отчет в окне приложения, но и управлять некоторыми опциями отчета. Например, можно изменить порядок сортировки данных отчета, модифицировать формулы выборки и группировки, модифицировать формулы отчета и т.д. Прежде чем использовать функции, управляющие опциями отчета, необходимо вызвать шесть основных функций:
Совместно с обязательным набором из шести функций можно использовать другие функции управления отчетом. В качестве примера можно рассмотреть функцию, устанавливающую формулу выборки - PESetSelectionFormula. Ее синтаксис:
PESetSelectionFormula (Print Job Handle, Formula String),
где Print Job Handle - указатель процесса печати, Formula String - текст формулы Crystal Reports.
Всего Crystal Reports 6.0 содержит 125 функций Print Engine - функции для управления данными, процессами печати, выводом в окно просмотра, принтером, экспортом, функции управления сортировкой , выборкой и группировкой, управлением форматом печати и т.д.
При помощи функций Print Engine можно просматривать отчет, менять его параметры, но нельзя менять дизайн отчета. Это утверждение относится к любым приложениям, написанным на любом языке программирования.
Существует несколько способов использования отчетов Crystal в приложениях, написанных на Delphi и C++Builder. Во-первых, можно непосредственно использовать функции Print Engine в коде, связанном с формой, или написать собственные компоненты, использующие такие функции. Во-вторых, можно воспользоваться готовым компонентом TCrpe, входящим в комплект поставки Crystal Reports 6.0, а также использовать компоненты третьих фирм. Можно использовать управляющий элемент Crystal Reports ActiveX. Наконец, можно управлять работой Crystal Reports Print Engine как сервером OLE Automation. Рассмотрим примеры использования каждого способа.
Для объявления функций Print Engine следует добавить в проект модуль CRPE32.PAS (или CRPE.PAS в случае использования версии Delphi 1.0), в котором объявлены все функции и структуры Report Engine API и сослаться на этот модуль в предложении uses. Все эти функции содержатся в библиотеке CRPE32 DLL ( CRPE DLL). После объявления функций их можно использовать внутри кода обработчиков событий.
Рассмотрим простейший пример использования Print Engine API. Для этой цели создадим форму, содержащую три кнопки и один компонент TOpenDialog следующего вида (рис. 1).
Рис. 1. Пример использования Print Engine API .
В качестве значения свойства Filter компонента TOpenDialog рекомендуется выбрать расширение *.rpt.
Создадим следующий код обработчиков событий, связанных с нажатием на кнопки:
unit crU1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, CRPE32; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; OpenDialog1: TOpenDialog; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; JN:word; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); VAR RepNam:PChar; begin if OpenDialog1.Execute then begin If PEOpenEngine then begin RepNam := StrAlloc(80); StrPCopy(RepNam, OpenDialog1.Filename); JN := PEOpenPrintJob(RepNam); if JN = 0 then ShowMessage('Ошибка открытия отчета'); StrDispose(RepNam); end else ShowMessage('Ошибка открытия отчета'); end; end; procedure TForm1.Button2Click(Sender: TObject); begin PEClosePrintJob(JN); PECloseEngine; Close; end; procedure TForm1.Button3Click(Sender: TObject); begin begin PEOutputToWindow(jn,'Пример использования Crystal Reports Print Engine',30,30,600,400,0,0) ; if PEStartPrintJob(JN, True) = False then ShowMessage('Ошибка вывода отчета'); end; end; end.
При нажатии на первую из кнопок производится выбор файла отчета с помощью стандартного диалога открытия файлов. При нажатии на вторую кнопку производится запуск Run-time-версии Crystal Reports и отображение отчета в стандартном окне (рис. 2):
Рис. 2. Отображение отчета с помощью функции PEStartPrintJob .
Следует помнить, что строковые параметры, передаваемые в функции Print Engine API, представляют собой тип данных PChar, а не стандартные строки, используемые в Pascal, поэтому для передачи таких параметров, как, например, имя отчета, следует осуществить преобразование типов с помощью функции StrPCopy. Отметим, что с помощью функций Print Engine API можно изменять довольно широкий спектр параметров отчета (Selection Formula, SQL Query, условия группировки и сортировки, параметры, связанные с печатью и отображением). Напомним также, что для успешной компиляции подобных приложений файл CRPE32.PAS должен находиться в том же каталоге, что и разрабатываемое приложение, либо в каталоге Delphi 3\Lib.
Для объявления функций Print Engine следует добавить в проект заголовочный файл CRPE.H, в котором объявлены все функции и структуры Print Engine API, и сослаться на него в тексте модуля, в котором из библиотеки CRPE32 DLL вызываются эти функции. Исходный текст примера, подобного рассмотренному выше примеру для Delphi, имеет следующий вид:
//------------------------------------------- #include <vcl.h> #pragma hdrstop #include "U1.h" #include "crpe.h" //------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; int JN; //------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { if (OpenDialog1->Execute()) { PEOpenEngine(); JN=PEOpenPrintJob((OpenDialog1->FileName).c_str()); if (JN==0) ShowMessage("Ошибка открытия отчета"); } } //------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { PEClosePrintJob(JN); PECloseEngine(); Close(); } //------------------------------------------- void __fastcall TForm1::Button3Click(TObject *Sender) { PEOutputToWindow(JN,"Пример использования Crystal Reports Print Engine",30,30,600,400,0,0) ; if (!PEStartPrintJob(JN,1)) ShowMessage("Ошибка вывода отчета"); } //-------------------------------------------
Отметим, что имя файла отчета, являющееся свойством компонента TOpenDialog, принадлежит к типу ANSIString, являющемуся классом С++Builder, созданным для совместимости с библиотекой VCL. Поэтому и в этом случае перед вызовом функций Print Engine API также требуется преобразование к стандартному для языка С++ строковому типу переменной, содержащей имя файла отчета.
В директории /SAMPAPPS/DELPHI содержится невизуальный компонент TCrpe Crpe_ico.bmp для версий Borland Delphi 1, 2 и 3, который в случае необходимости его использования должен быть установлен в палитру компонентов (по умолчанию - на страницу DataAccess). Этот компонент реализует почти все возможности, предоставляемые Print Engine API, позволяя избежать написания соответствующего кода. Для включения компонента в приложение следует поместить его на форму и установить необходимые значения его свойств (которых у этого компонента около сотни - для определения параметров, связанных с переменными отчета, печатью и отображением данных, типом окна, в котором отображается отчет, и т.д.). Минимально необходимым среди них является свойство ReportName - имя файла отчета. Для отображения отчета в стандартном окне, подобном изображенному на рис. 2, и вывода на принтер используется метод Execute этого компонента.
Отметим, что с помощью установки значений ряда свойств этого компонента на этапе выполнения можно менять во время выполнения характеристики отчета, такие как значения специальных полей, текст SQL-запроса, условия отбора данных, свойства, связанные с отображением и печатью. Рассмотрим простейший пример подобного управления отчетом. С этой целью создадим простейший отчет на основе таблицы Items.db из базы данных DBDEMOS, входящей в комплект поставки Delphi. Затем создадим приложение, на главную форму которого поместим компонент TEdit, две кнопки и, разумеется, компонент TCrpe (рис.3).
Рис. 3. Приложение для тестирования возможности управления отчетом на этапе выполнения.
Создадим обработчик события, связанного с нажатием на кнопку "Открыть отчет":
procedure TForm1.Button1Click(Sender: TObject); begin if edit1.text='' then Crpe1.SelectionFormula.Strings[0]:='' else Crpe1.SelectionFormula.Strings[0]:='{items.ItemNo} = ' + Edit1.Text; if not Crpe1.execute then ShowMessage('Ошибка открытия отчета'); end;
В этом обработчике события на основе значения, введенного пользователем в компонент TEdit, меняется значение свойства SelectionFormula компонента TCrpe, и в результате пользователь получает в окне отчета не всю таблицу целиком, а только записи, в которых значение поля ItemNo равно введенному пользователем числу (рис.4). Для работоспособности данного кода рекомендуется в качестве значения свойства SelectionFormula ввести хотя бы одну пустую строку, чтобы в соответствующем строковом массиве был хотя бы один элемент.
Рис. 4. Результат установки значения поля SelectionFormula на этапе выполнения.
В качестве примера рассмотрим компоненту фирмы SupraSoft Ltd..
Этот компонент поставляется в виде отдельного пакета. Для его включения в палитру компонентов следует в выбрать в меню Delphi 3 пункт Component / Install Packages... В диалоговой панели Project Options нужно выбрать страницу Packages, в которой нужно нажать на кнопку Add и в появившемся диалоге Add Design Package выбрать файл crysdc15.dpc (Package collection) из комплекта поставки компонент SupraSoft. После инсталляции и закрытия с помощью кнопки OK диалога Project Options в палитре компонентов появится дополнительная страница Supra с единственным компонентом TCrystalDesign supr_ico.bmp. Этот компонент, в отличие от компонента TCrpe, является визуальным и позволяет отображать "живые" данные из отчета непосредственно на этапе проектирования формы, которая при этом фактически заменяет собой стандартное окно Crystal Reports Run-time на этапе выполнения. Функциональность этого компонента и возможности динамического управления отчетом на этапе выполнения примерно те же, что и у компонента TCrpe.
В качестве иллюстрации создадим пример, аналогичный предыдущему, поместив на форму компонент TEdit, две кнопки и компонент TCrystalDesign. Создадим следующий обработчик события, связанного с нажатием на одну из кнопок:
procedure TForm1.Button1Click(Sender: TObject); begin CrystalDesign1.ResetContent:=true; if edit1.text='' then CrystalDesign1.SelectionFormula.Clear else CrystalDesign1.SelectionFormula.Add('{items.ItemNo} = ' + Edit1.Text); CrystalDesign1.Active:=True; end;
Отметим, что метод ResetContent компонента TCrystalDesign закрывает отчет, чем в данном случае мы и воспользовались. Результат работы данного примера приведен на рис. 5.
Рис. 5. Результат установки значения поля SelectionFormula на этапе выполнения.
К сожалению, оба компонента, и TCrpe, и TCrystalDesign, поставляются на сегодняшний день только в варианте для Delphi, и не могут быть установлены в палитру компонентов C++Builder, так как поставляются без исходных текстов. Однако с помощью функций Print Engine API можно также осуществить динамическое управление отчетом, правда, с несколько меньшим комфортом, чем при использовании готовых компонентов. Например, изменение формулы для отбора записей в готовом отчете согласно какому-либо критерию в этом случае осуществляется с помощью оператора примерно следующего вида:
PESetSelectionFormula(JN,"{items.ItemNo} = 2");
Отметим также, что готовые компоненты для управления отчетами также создаются с помощью функций Print Engine API, и возможности творчества в этом направлении поистине безграничны...
Еще одним вариантом использования Crystal Reports в приложениях является использование Crystal Report Engine как OLE Automation-сервера. В справочной системе Crystal Reports имеется подробное описание иерархии вложенных объектов и их методов (и внушительный набор примеров для Visual Basic, аналоги которых несложно создать и на Pascal). В этом случае пример для Delphi, аналогичный рассмотренному выше, выглядит следующим образом:
unit Uole1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,ComObj; type TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; Button2: TButton; Label1: TLabel; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; rep,r:variant; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin rep:=CreateOleObject('Crystal.CRPE.Application'); r:=rep.OpenReport('d:\Report2.rpt'); r.RecordSelectionFormula := '{items.ItemNo} = '+Edit1.Text; r.Preview; end; procedure TForm1.Button2Click(Sender: TObject); begin Close; end; end.
Отметим, однако, что использование OLE Automation - не самый выгодный с точки зрения производительности способ управления отчетами.
В комплект поставки Crystal Reports Professional входят также ActiveX-компонент для управления Run-time-версией Crystal Reports. Этот компонент ax.bmp может быть установлен в палитру компонентов Delphi или С++Builder и далее может быть использован при проектировании приложений, как и любой невизуальный компонент. Этот компонент обладает набором свойств и методов, более или менее сходным с соответствущим VCL-компонентом TCrpe.
В качестве иллюстрации выполним тот же пример, что и в предыдущем случае, но с использованием Crystal Reports ActiveX. Создадим форму, содержащую ActiveX-компонент TCrystalReport, а так же две кнопки и компонент TEdit:
Рис.6. Пример использования Crystal Reports ActiveX
Crystal Reports ActiveX обладает весьма удобным редактором свойств, позволяющим определить ряд опций уже готового отчета.
Рис.7. Редактор свойств Crystal Reports ActiveX
Создадим обработчик события, связанного с нажатием на кнопку "Открыть отчет"
procedure TForm1.Button1Click(Sender: TObject); begin if edit1.text='' then CrystalReport1.SelectionFormula:='' else CrystalReport1.SelectionFormula:='{items.ItemNo} = ' + Edit1.Text; if not (CrystalReport1.PrintReport=0) then ShowMessage('Ошибка открытия отчета'); end;
В результате нажатия пользователем на кнопку пользователь получает в окне отчета записи, в которых значение поля ItemNo равно введенному пользователем числу (то есть то же самое, что изображено на рис.4).
Отметим, что Crystal Reports ActiveX можно с успехом использовать в приложениях, созданных с помощью любого другого средства разработки, использующего управляющие элементы ActiveX.
Отметим также, что для пользователей Delphi 1.0 в комплекте поставки 16-разрядной версии Crystal Reports Professional имеется сходный по функциональности управляющий элемент VBX, который также может быть установлен в палитру компонентов и использован в 16-разрядных приложениях.
Таким образом, на сегодняшний день существует довольно богатый выбор способов, с помощью которых можно управлять отчетами Crystal Reports из средств разработки - как с использованием вызовов функций Print Engine API, так и с использованием OLE-технологии.