----В предыдущей работе автора, использующего Delphi для разработки базы данных, пользователь выдвинул такое требование: динамически формировать отчеты на основе собственных результатов запросов и затем распечатывать их. После долгих исследований автор использовал метод динамического создания элементов управления QuickReport для удовлетворения потребностей пользователей. Этот метод объясняется ниже, в надежде дать несколько полезных советов друзьям, которым предстоит выполнить аналогичную работу.
1. Основные идеи
----Сначала запишите некоторые параметры запроса (например, команды SQL, имена полей, ширину полей и т. д.) во временный файл в определенном формате. При создании отчета просто динамически создавайте различные элементы управления QuickReport на основе параметров, записанных во временном файле.
2. Реализация программы
2.1 Формат временного файла
----Формат временного файла может быть настроен в соответствии с потребностями. Автор использует формат файла INI. Delphi предоставляет класс TInifile, который делает очень удобным работу с файлами формата INI в Delphi. О формате и конкретных операциях с INI-файлами написано много статей, поэтому я не буду здесь вдаваться в подробности. Формат временного файла следующий:
Отчет.ini
:Подробности отчета
[rep_detail]
Название=XXXXX таблица
: настройки бумаги для печати: 1 — бумага A4, 2 — бумага B5, 3 — 16K.
Страница=1
: Режим печати, 1 означает горизонтальную печать, 0 означает вертикальную печать.
Ориентация=1
: Количество полей, включенных в отчет.
столбцы = 8
:Информация о компоненте TQurey
[КурейДанные]
: Содержимое команды SQL компонента Tqurey в компоненте QuickReport.
Sql_command = выберите V_XM,V_JGZW,V_BMMC,V_DWMC,V_DWZW,V_ZY,V_ZC,V_BGDH из Hvzzjg, где V_XM LIKE '李%'
[col_0]
Заголовок=Имя
DataFiled=V_XM
Ширина=60
…
…
2.2 Динамическое создание отчетов QuickReport
--- Основные элементы управления отчета и их основные настройки свойств следующие:
Имя элемента управления | Имя класса | свойство | значение атрибута |
Форма_rep | ТФорм | подпись | динамический отчет |
Быстрый повтор | TQuickRep | Набор данных | REP_QUERY |
ДетальБэнд1 | TQRBand | Тип полосы | rbDetail |
Заголовок столбцаBand1 | TQRBand | Тип полосы | рбКолумнхедер |
REP_источник данных | TDataSource | Набор данных | Rep_Query |
Rep_Query | TQuery | Имя базы данных | БАЗА РЕПДАННЫХ |
Rep_Database | TDatabase | Подключено | Истинный |
Параметры.Строки | 'ИМЯ СЕРВЕРА=XXX 'МАМА ПОЛЬЗОВАТЕЛЯ=XXX' 'ПАРОЛЬ=XXX' | ||
Имя базы данных | БАЗА РЕПДАННЫХ |
Элементы управления, представленные в таблице выше, были созданы в программе вручную. Другие элементы управления должны создаваться в программе динамически.
2.2.2 Основные процедуры
единица f_rep;
интерфейс
использует
Windows, сообщения, SysUtils, варианты, классы, графика, элементы управления, формы,
Диалоги, ExtCtrls, QuickRpt, QRCtrls, DB, DBTables, ПРИНТЕРЫ, QRPrntr, inifiles,
TeeProcs, TeEngine, DbChart, QRTEE;
тип
TForm_rep = класс (TForm)
QuickRep: TQuickRep;
ДеталБанд1: TQRBand;
ColumnHeaderBand1: TQRBand;
REP_DataSource: TDataSource;
REP_QUERY: TQuery;
Rep_Database: TDatabase;
процедура TForm_rep.QuickRepAfterPreview(Sender: TObject);//После просмотра освободить все созданные компоненты
частный
{Частные заявления}
общественный
{Публичные заявления}
конец;
вар Form_rep: TForm_Rep;
type //Сводная информация отчета
C_rep_Summary=запись
Title:string;//Название отчета
Page:TQRPaperSize;//Настройки страницы отчета, какой тип бумаги используется
Orientation:TPrinterOrientation;//Настройка страницы отчета, горизонтальная или вертикальная
Columns:integer;//Количество столбцов, включенных в отчет
конец;
тип
C_Rep_Col_Summary=record//Сводная информация по столбцам отчета
Caption:string;//название столбца отчета
DataFiled:string;//Имя поля в базе данных, соответствующее столбцу отчета
Width:integer;//ширина столбца отчета
конец;
тип
C_Rep_Col_Sum_store=record //Сводная информация о хранении столбцов отчета
Caption_array: массив строк;
DataFiled_array:массив строк;
Width_array:массив целых чисел;
конец;
вар
Rep_Summary:C_rep_Summary;
Rep_Col_Summary:C_Rep_Col_Summary;
Rep_Col_Sum_store:C_Rep_Col_Sum_store;
Colum_Name: массив tQRRichText;
Colum_Data: массив TQRDBRichText;
C_Query:TQuery;
процедура Form_rep_init();
процедура DynCreat_TQRDBText(Colum_Num:integer;Colum_Height:integer;DataSet_Name:TQuery);//Динамически создаем элемент управления TQRDBText
процедура DynCreat_TQRRichtext(Colum_Num:integer);//Динамически создаем элемент управления TQRRichtext
процедура DynCreat_TQuery(Inifile_Name:Tinifile);//оператор SQL для динамического создания элемента управления TQuery
процедура Get_PageCount();//Получаем общее количество напечатанных страниц
функция Open_IniFile():Tinifile;//Открыть временный файл
процедура Read_Col_Summary(Inifile_Name:Tinifile);//Читаем сводную информацию столбцов отчета
процедура Read_Rep_Summary(Inifile_Name:Tinifile);//Читать сводную информацию отчета
function Rep_chanslateOrientation(var Rep_Orientation:integer):TPrinterOrientation;//Преобразуем настройки режима печати
function Rep_chanslatepage(var Rep_Page:integer):TQRPaperSize;//Преобразуем настройку размера страницы печати
выполнение
{$R *.dfm}
function Rep_chanslatepage(var Rep_Page:integer):TQRPaperSize;//Преобразуем настройку типа страницы печати
начинать
дело Rep_Page из
1: начать
результат:=A4;
Form_rep.QuickRep.PrinterSettings.PaperSize:=A4;
конец;
2: начать
результат:=B5;
Form_rep.QuickRep.PrinterSettings.PaperSize:=B5
конец;
3: начать
результат: = Исполнительный;
Form_rep.QuickRep.PrinterSettings.PaperSize:=Executive;
конец;
конец;
конец;
function Rep_chanslateOrientation(var Rep_Orientation:integer):TPrinterOrientation;//Преобразуем настройки режима печати
начинать
случай Rep_Orientation of
0: начать
result:=poPortrait;//0 вертикально
Form_rep.QuickRep.PrinterSettings.Orientation:=poPortrait;
конец;
1: начать
result:=poLandscape;//1 горизонтально
Form_rep.QuickRep.PrinterSettings.Orientation:=poLandscape;
конец;
конец;
конец;
функция Open_IniFile():Tinifile;//Открыть временный файл
вар Имя файла: строка;
Ini_Filename: строка;
начинать
Имя файла:='Report.ini';
Ini_Filename:=File_Path+Filename;
Результат:=Tinifile.Create(Ini_Filename);
конец;
процедура Read_Rep_Summary(Inifile_Name:Tinifile);//Читать сводную информацию отчета
вар Rep_Page, Rep_Orientation: целое число;
начинать
Rep_Page:=Inifile_Name.Readinteger('rep_detail','Page',1);
Rep_Orientation:=Inifile_Name.Readinteger('rep_detail','Orientation',0);
с помощью Rep_Summary сделайте
начинать
Столбцы:=Inifile_Name.Readinteger('rep_detail','columns',0);
Title:=Inifile_Name.Readstring('rep_detail','Title','Безымянный отчет');
page:=rep_chanslatepage(Rep_Page);//Преобразуем размер страницы для печати
Orientation:=rep_chanslateOrientation(Rep_Orientation);//Преобразуем настройки режима печати
конец;
конец;
процедура Read_Col_Summary(Inifile_Name:Tinifile);//Читаем сводную информацию столбцов отчета
вар i_count: целое число;
начинать
//Сохраняем информацию о столбце в массиве
с помощью Rep_Col_Sum_store сделайте
начинать
SetLength(Caption_array,rep_Summary.Columns);
SetLength(DataFiled_array,rep_Summary.Columns);
SetLength(Width_array,rep_Summary.Columns);
конец;
для i_count:=0 для Rep_Summary.Columns-1 сделать
начинать
с помощью Rep_Col_Summary сделайте
начинать
Caption:=Inifile_Name.Readstring('col_'+inttostr(i_count),'Caption','Unnamed');
DataFiled:=Inifile_Name.Readstring('col_'+inttostr(i_count),'DataFiled','');
Ширина:=Inifile_Name.Readinteger('col_'+inttostr(i_count),'Width',0);
конец;
с помощью Rep_Col_Sum_store сделайте
начинать
Caption_array[i_count]:=Rep_Col_Summary.Caption;
DataFiled_array[i_count]:=Rep_Col_Summary.DataFiled;
Width_array[i_count]:=Rep_Col_Summary.Width;
конец;
конец;
конец;
процедура DynCreat_TQRRichtext(Colum_Num:integer);//Динамически создаем элемент управления TQRRichtext, который используется для отображения китайского имени каждого столбца в отчете
вар Colum_Name_list: TStrings;
начинать
Colum_Name[Colum_Num]:=tQRRichtext.Create(application); //Создаем элемент управления TQRRichtext
Colum_Name[Colum_Num].Parent:=Form_rep.ColumnHeaderBand1;
Colum_Name[Colum_Num].Frame.DrawTop:=true;
Colum_Name[Colum_Num].Frame.DrawBottom:=true;
Form_rep.ColumnHeaderBand1.Height:=40;
Colum_Name[Colum_Num].Высота:=40;
Colum_Name[Colum_Num].Font.Height:=-14;
Colum_Name[Colum_Num].Font.Name:='Адское тело';
Colum_Name[Colum_Num].Top:=0;
Colum_Name[Colum_Num].Alignment:=taCenter;
Colum_Name[Colum_Num].AutoStretch:=false;
//Рисуем строки таблицы
Colum_Name[Colum_Num].Frame.Style:=psSolid;
Имя_столбца[Номер_столбца].Кадр.Ширина:=1;
Colum_Name[Colum_Num].Frame.DrawRight:=true;
Colum_Name[Colum_Num].Frame.DrawBottom:=true;
если Colum_Num=0, то
начинать
Colum_Name[Colum_Num].Frame.DrawLeft:=true;
конец;
//Назначаем информацию в записи RRep_Col_Sum_store столбцу Colum_Name
Colum_Name_list:=TStringList.Create;
Colum_Name_list.Add(Rep_Col_Sum_store.Caption_array[Colum_Num]);
Colum_Name[Colum_Num].Lines:=Colum_Name_list;
Colum_Name[Colum_Num].Width:=Rep_Col_Sum_store.Width_array[Colum_Num];
Colum_Name[Colum_Num].Visible:=true;
//Рассчитываем левую границу
если Colum_Num>0, то
Имя_столбца[Num_столбца].Left:=Имя_столбца[Num_столбца-1].Left+Имя_столбца[Num_столбца-1].Ширина
еще
Имя_столбца[Номер_столбца].Слева:=0;
конец;
Примечание. Здесь используется элемент управления TQRRichtext, поскольку элемент управления TQRRichtext может автоматически переносить строки, если имя слишком длинное.
процедура DynCreat_TQRDBText(Colum_Num:integer;Colum_Height:integer;DataSet_Name:TQuery);//Динамически создаем элемент управления TQRDBText, который используется для отображения значения каждого столбца
начинать
Colum_Data[Colum_Num]:=tQRDBText.Create(приложение);
Colum_Data[Colum_Num].Parent:=Form_rep.DetailBand1;
//Устанавливаем набор данных
Colum_Data[Colum_Num].DataSet:=DataSet_Name;
//Установим для свойства массива Colum_Data.DateField имя поля в C_Rep_Col_Sum_store
Colum_Data[Colum_Num].DataField:=Rep_Col_Sum_store.DataFiled_array[Colum_Num];
Colum_Data[Colum_Num].Width:=Rep_Col_Sum_store.Width_array[Colum_Num];
Colum_Data[Colum_Num].Height:=Colum_Height;
Form_rep.DetailBand1.Height:=Colum_Height;
Colum_Data[Colum_Num].Top:=0;
Colum_Data[Colum_Num].AutoSize:=false;
Colum_Data[Colum_Num].AutoStretch:=false;
Colum_Data[Colum_Num].WordWrap:=false;
Colum_Data[Colum_Num].Visible:=true;
//Рисуем строки таблицы
Colum_Data[Colum_Num].Frame.Style:=psSolid;
Colum_Data[Colum_Num].Frame.DrawRight:=true;
Colum_Data[Colum_Num].Frame.DrawBottom:=true;
если Colum_Num=0, то
Colum_Data[Colum_Num].Frame.DrawLeft:=true;
//Рассчитываем левую границу
если Colum_Num>0, то
Colum_Data[Colum_Num].Left:=Colum_Data[Colum_Num-1].Left+Colum_Data[Colum_Num-1].Width
еще
Colum_Data[Colum_Num].Left:=0;
конец;
процедура DynCreat_TQuery(Inifile_Name:Tinifile);//Динамически устанавливает оператор SQL элемента управления TQuery
вар
Sql_command: строка;
начинать
Flag_CreatQuery:=false;
Sql_command:=Inifile_Name.Readstring('QureyData','Sql_Command','');
Form_rep.REP_QUERY.Закрыть;
Form_rep.REP_QUERY.SQL.Очистить;
Form_rep.REP_QUERY.SQL.Append(Sql_command);
если не Form_rep.REP_QUERY.Prepared, то
Form_rep.REP_QUERY.Prepare;
пытаться
Form_rep.REP_QUERY.ExecSQL;
Form_rep.REP_QUERY.Active:=true;
Form_rep.REP_QUERY.AutoCalcFields:=true;
Flag_CreatQuery:=истина;
кроме
Application.MessageBox('Ошибка оператора SQL!','Системная подсказка',MB_ICONWARNING);
Flag_CreatQuery:=false;
конец;
конец;
процедура Form_rep_init();
вар i_count: целое число;
Rep_IniFile:Tinifile;//