----No trabalho anterior do autor usando Delphi para desenvolver um banco de dados, o usuário apresentou tal requisito: gerar relatórios dinamicamente com base nos resultados de suas próprias consultas e depois imprimi-los. Depois de muita exploração, o autor utilizou o método de geração dinâmica de controles QuickReport para atender às necessidades dos usuários. Este método é explicado abaixo, na esperança de fornecer algumas dicas úteis para amigos que têm trabalhos semelhantes a fazer.
1. Ideias básicas
----Primeiro escreva alguns parâmetros de consulta (como comandos SQL, nomes de campos, larguras de campos, etc.) em um arquivo temporário em um determinado formato. Ao gerar um relatório, basta gerar dinamicamente diversos controles QuickReport com base nos parâmetros registrados no arquivo temporário.
2. Implementação do programa
2.1 Formato de arquivo temporário
----O formato do arquivo temporário pode ser personalizado de acordo com as necessidades. O autor usa o formato de arquivo INI. Delphi fornece uma classe TInifile, o que torna muito conveniente operar arquivos no formato INI no Delphi. Existem muitos artigos sobre o formato e operações específicas dos arquivos INI, então não entrarei em detalhes aqui. O formato do arquivo temporário é o seguinte:
Relatório.ini
:Detalhes do relatório
[rep_detail]
Título = tabela XXXXX
: Configurações de papel de impressão, 1 é papel A4, 2 é papel B5, 3 é 16K
Página=1
: Modo de impressão, 1 significa impressão horizontal, 0 significa impressão vertical.
Orientação=1
:Número de campos incluídos no relatório
colunas=8
:Informações do componente TQurey
[QureyData]
: Conteúdo do comando SQL do componente Tqurey no componente QuickReport
Sql_command=selecione V_XM,V_JGZW,V_BMMC,V_DWMC,V_DWZW,V_ZY,V_ZC,V_BGDH de Hvzzjg onde V_XM LIKE '李%'
[col_0]
Legenda=Nome
DadosArquivado=V_XM
Largura=60
…
…
2.2 Gerar relatórios QuickReport dinamicamente
--- Os principais controles do relatório e suas principais configurações de propriedades são os seguintes
Nome do controle | Nome da classe | propriedade | valor do atributo |
Form_rep | Formulário | rubrica | relatório dinâmico |
QuickRep | TQuickRep | Conjunto de dados | REP_QUERY |
DetalheBand1 | Banda TQRB | Tipo de banda | rbDetalhe |
ColumnHeaderBand1 | Banda TQRB | Tipo de banda | rbColumnHeader |
REP_DataSource | TDataSource | Conjunto de dados | Rep_Query |
Rep_Query | Consulta | Nome do banco de dados | REPDATABASE |
Rep_Database | Banco de dados T | Conectado | Verdadeiro |
Parâmetros.Strings | 'NOME DO SERVIDOR=XXX 'USUÁRIO MAME=XXX' 'SENHA=XXX' | ||
Nome do banco de dados | REPDATABASE |
Os controles mostrados na tabela acima foram criados manualmente no programa. Outros controles devem ser criados dinamicamente no programa.
2.2.2 Principais procedimentos
unidade f_rep;
interface
usa
Windows, Mensagens, SysUtils, Variantes, Classes, Gráficos, Controles, Formulários,
Diálogos, ExtCtrls, QuickRpt, QRCtrls, DB, DBTables,PRINTERS,QRPrntr,inifiles,
TeeProcs, TeEngine, DbChart, QRTEE;
tipo
TForm_rep = classe(TForm)
QuickRep: TQuickRep;
DetailBand1: Banda TQRB;
ColumnHeaderBand1: TQRBand;
REP_DataSource:TDataSource;
REP_QUERY:TQuery;
rep_Database: TDatabase;
procedimento TForm_rep.QuickRepAfterPreview(Sender: TObject);//Após navegar, libere todos os componentes criados
privado
{Declarações privadas}
público
{Declarações públicas}
fim;
var Form_rep:TForm_Rep;
type //Informações resumidas do relatório
C_rep_Summary=registro
Title:string;//Título do relatório
Page:TQRPaperSize;//As configurações da página do relatório, que tipo de papel é usado
Orientation:TPrinterOrientation;//A configuração da página do relatório, seja horizontal ou vertical
Columns:integer;//Número de colunas incluídas no relatório
fim;
tipo
C_Rep_Col_Summary=registro//Informações resumidas das colunas do relatório
Caption:string; //nome da coluna do relatório
DataFiled:string;//O nome do campo no banco de dados correspondente à coluna do relatório
Width:integer;//largura da coluna do relatório
fim;
tipo
C_Rep_Col_Sum_store=record //Armazena informações resumidas das colunas do relatório
Caption_array:matriz de string;
DataFiled_array:matriz de string;
Width_array:matriz de inteiros;
fim;
var
rep_Summary:C_rep_Summary;
Rep_Col_Summary:C_Rep_Col_Summary;
Rep_Col_Sum_store:C_Rep_Col_Sum_store;
Colum_Name: array de tQRRichText;
Colum_Data:array de TQRDBRichText;
C_Query:TQuery;
procedimento Form_rep_init();
procedimento DynCreat_TQRDBText(Colum_Num:integer;Colum_Height:integer;DataSet_Name:TQuery);//cria dinamicamente o controle TQRDBText
procedimento DynCreat_TQRRichtext(Colum_Num:integer);//cria dinamicamente o controle TQRRichtext
procedimento DynCreat_TQuery(Inifile_Name:Tinifile);//instrução SQL para criar dinamicamente o controle TQuery
procedure Get_PageCount(); //Obtém o número total de páginas impressas
function Open_IniFile():Tinifile;//Abre arquivo temporário
procedimento Read_Col_Summary(Inifile_Name:Tinifile);//Lê informações resumidas das colunas do relatório
procedimento Read_Rep_Summary(Inifile_Name:Tinifile);//Lê informações resumidas do relatório
function rep_chanslateOrientation(var Rep_Orientation:integer):TPrinterOrientation;//Converte as configurações do modo de impressão
function rep_chanslatepage(var Rep_Page:integer):TQRPaperSize;//Converte a configuração do tamanho da página de impressão
implementação
{$R *.dfm}
function rep_chanslatepage(var Rep_Page:integer):TQRPaperSize;//Converte a configuração do tipo de página de impressão
começar
caso Rep_Página de
1: começar
resultado:=A4;
Form_rep.QuickRep.PrinterSettings.PaperSize:=A4;
fim;
2: começar
resultado:=B5;
Form_rep.QuickRep.PrinterSettings.PaperSize:=B5
fim;
3: começar
resultado:=Executivo;
Form_rep.QuickRep.PrinterSettings.PaperSize:=Executivo;
fim;
fim;
fim;
function rep_chanslateOrientation(var Rep_Orientation:integer):TPrinterOrientation;//Converte as configurações do modo de impressão
começar
caso Rep_Orientação de
0: começar
resultado:=poPortrait;//0 é vertical
Form_rep.QuickRep.PrinterSettings.Orientation:=poPortrait;
fim;
1: começar
resultado:=poPaisagem;//1 é horizontal
Form_rep.QuickRep.PrinterSettings.Orientation:=poLandscape;
fim;
fim;
fim;
function Open_IniFile():Tinifile;//Abre arquivo temporário
var Nome do arquivo: string;
Ini_Filename:string;
começar
Nome do arquivo:='Relatório.ini';
Ini_Filename:=Caminho_do_arquivo+Nome do arquivo;
Resultado:=Tinifile.Create(Ini_Filename);
fim;
procedimento Read_Rep_Summary(Inifile_Name:Tinifile);//Lê as informações resumidas do relatório
var Rep_Page,Rep_Orientation:integer;
começar
rep_Page:=Inifile_Name.Readinteger('rep_detail','Página',1);
Rep_Orientation:=Inifile_Name.Readinteger('rep_detail','Orientation',0);
com rep_Summary faça
começar
Colunas:=Inifile_Name.Readinteger('rep_detail','colunas',0);
Title:=Inifile_Name.Readstring('rep_detail','Title','Relatório sem nome');
page:=rep_chanslatepage(Rep_Page);//Converte o tamanho da página de impressão
Orientation:=rep_chanslateOrientation(Rep_Orientation);//Converte as configurações do modo de impressão
fim;
fim;
procedimento Read_Col_Summary(Inifile_Name:Tinifile);//Lê informações resumidas das colunas do relatório
var i_count:inteiro;
começar
//Salva as informações da coluna no array
com Rep_Col_Sum_store faça
começar
SetLength(Caption_array,rep_Summary.Columns);
SetLength(DataFiled_array,rep_Summary.Columns);
SetLength(Largura_array,rep_Summary.Colunas);
fim;
para i_count:=0 para rep_Summary.Columns-1 faça
começar
com Rep_Col_Summary faça
começar
Legenda:=Inifile_Name.Readstring('col_'+inttostr(i_count),'Caption','Sem nome');
DataFiled:=Inifile_Name.Readstring('col_'+inttostr(i_count),'DataFiled','');
Largura:=Inifile_Name.Readinteger('col_'+inttostr(i_count),'Largura',0);
fim;
com Rep_Col_Sum_store faça
começar
Caption_array[i_count]:=Rep_Col_Summary.Caption;
DataFiled_array[i_count]:=Rep_Col_Summary.DataFiled;
Largura_array[i_count]:=Rep_Col_Summary.Width;
fim;
fim;
fim;
procedimento DynCreat_TQRRichtext(Colum_Num:integer);//cria dinamicamente um controle TQRRichtext, que é usado para exibir o nome chinês de cada coluna no relatório
var Colum_Name_list:TStrings;
começar
Colum_Name[Colum_Num]:=tQRRichtext.Create(application); //Criar controle TQRRichtext
Colum_Name[Colum_Num].Parent:=Form_rep.ColumnHeaderBand1;
Colum_Name[Colum_Num].Frame.DrawTop:=true;
Nome_coluna[Número_coluna].Frame.DrawBottom:=true;
Form_rep.ColumnHeaderBand1.Height:=40;
Nome_coluna[Número_coluna].Altura:=40;
Nome_coluna[Número_coluna].Font.Height:=-14;
Colum_Name[Colum_Num].Font.Name:='Corpo do inferno';
Nome_coluna[Número_coluna].Topo:=0;
Nome_coluna[Número_coluna].Alinhamento:=taCenter;
Nome_Coluna[Número_Coluna].AutoStretch:=false;
//desenha as linhas da tabela
Nome_coluna[Número_coluna].Frame.Style:=psSolid;
Nome_coluna[Número_coluna].Quadro.Largura:=1;
Colum_Name[Colum_Num].Frame.DrawRight:=true;
Nome_coluna[Número_coluna].Frame.DrawBottom:=true;
se Colum_Num=0 então
começar
Nome_coluna[Número_coluna].Frame.DrawLeft:=true;
fim;
//Atribuir as informações do registro RRep_Col_Sum_store para Colum_Name
Colum_Name_list:=TStringList.Create;
Colum_Name_list.Add(Rep_Col_Sum_store.Caption_array[Colum_Num]);
Nome_coluna[Número_coluna].Linhas:=Nome_coluna_lista;
Nome_Coluna[Número_Coluna].Largura:=Rep_Col_Sum_store.Width_array[Número_Coluna];
Nome_coluna[Número_coluna].Visível:=true;
//Calcula o limite esquerdo
se Coluna_Num>0 então
Nome_coluna[Número_coluna].Esquerda:=Nome_coluna[Número_coluna-1].Esquerda+Nome_coluna[Número_coluna-1].Largura
outro
Nome_coluna[Número_coluna].Esquerda:=0;
fim;
Nota: O controle TQRRichtext é usado aqui porque o controle TQRRichtext pode quebrar linhas automaticamente quando o nome for muito longo.
procedimento DynCreat_TQRDBText(Colum_Num:integer;Colum_Height:integer;DataSet_Name:TQuery);//Cria dinamicamente um controle TQRDBText, que é usado para exibir o valor de cada coluna
começar
Colum_Data[Colum_Num]:=tQRDBText.Create(aplicativo);
Colum_Data[Colum_Num].Parent:=Form_rep.DetailBand1;
//Definir o conjunto de dados
Colum_Data[Colum_Num].DataSet:=DataSet_Name;
//Defina a propriedade Colum_Data.DateField do array para o nome do campo em 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].Topo:=0;
Colum_Data[Colum_Num].AutoSize:=false;
Colum_Data[Colum_Num].AutoStretch:=false;
Colum_Data[Colum_Num].WordWrap:=false;
Colum_Data[Colum_Num].Visível:=true;
//desenha as linhas da tabela
Colum_Data[Colum_Num].Frame.Style:=psSolid;
Colum_Data[Colum_Num].Frame.DrawRight:=true;
Colum_Data[Colum_Num].Frame.DrawBottom:=true;
se Colum_Num=0 então
Colum_Data[Colum_Num].Frame.DrawLeft:=true;
//Calcula o limite esquerdo
se Coluna_Num>0 então
Colum_Data[Colum_Num].Left:=Colum_Data[Colum_Num-1].Left+Colum_Data[Colum_Num-1].Width
outro
Colum_Data[Colum_Num].Esquerda:=0;
fim;
procedimento DynCreat_TQuery(Inifile_Name:Tinifile); // Define dinamicamente a instrução SQL do controle TQuery
var
comando_sql:string;
começar
Flag_CreatQuery:=falso;
Sql_command:=Inifile_Name.Readstring('QureyData','Sql_Command','');
Form_rep.REP_QUERY.Fechar;
Form_rep.REP_QUERY.SQL.Clear;
Form_rep.REP_QUERY.SQL.Append(Sql_command);
se não for Form_rep.REP_QUERY.Prepared então
Form_rep.REP_QUERY.Prepare;
tentar
Form_rep.REP_QUERY.ExecSQL;
Form_rep.REP_QUERY.Active:=true;
Form_rep.REP_QUERY.AutoCalcFields:=true;
Flag_CreatQuery:=verdadeiro;
exceto
Application.MessageBox('Erro de instrução SQL!','Prompt do sistema',MB_ICONWARNING);
Flag_CreatQuery:=falso;
fim;
fim;
procedimento Form_rep_init();
var i_count:inteiro;
Rep_IniFile:Tinifile;//