----En el trabajo anterior del autor que utiliza Delphi para desarrollar una base de datos, el usuario planteó tal requisito: generar dinámicamente informes basados en los resultados de su propia consulta y luego imprimirlos. Después de mucha exploración, el autor utilizó el método de generar dinámicamente controles QuickReport para satisfacer las necesidades de los usuarios. Este método se explica a continuación, con la esperanza de brindar algunos consejos útiles para amigos que tienen un trabajo similar que hacer.
1. Ideas básicas
---- Primero escriba algunos parámetros de consulta (como comandos SQL, nombres de campos, anchos de campos, etc.) en un archivo temporal en un formato determinado. Al generar un informe, simplemente genere dinámicamente varios controles QuickReport según los parámetros registrados en el archivo temporal.
2. Implementación del programa
2.1 Formato de archivo temporal
----El formato del archivo temporal se puede personalizar según las necesidades. El autor utiliza el formato de archivo INI. Delphi proporciona una clase TInifile, lo que hace que sea muy conveniente operar archivos en formato INI en Delphi. Hay muchos artículos sobre el formato y las operaciones específicas de los archivos INI, por lo que no entraré en detalles aquí. El formato del archivo temporal es el siguiente:
Informe.ini
: Detalles del informe
[representante_detalle]
Título=tabla XXXXX
: Configuración del papel de impresión, 1 es papel A4, 2 es papel B5, 3 es 16K
Página=1
: Modo de impresión, 1 significa impresión horizontal, 0 significa impresión vertical.
Orientación=1
: Número de campos incluidos en el informe
columnas=8
: Información del componente TQurey
[QureyDatos]
: Contenido del comando SQL del componente Tqurey en el componente QuickReport
Sql_command=seleccione V_XM,V_JGZW,V_BMMC,V_DWMC,V_DWZW,V_ZY,V_ZC,V_BGDH de Hvzzjg donde V_XM ME GUSTA '李%'
[col_0]
Título=Nombre
Datos archivados=V_XM
Ancho=60
…
…
2.2 Generar dinámicamente informes QuickReport
--- Los controles principales del informe y la configuración de sus propiedades principales son los siguientes
Nombre del control | nombre de clase | propiedad | valor del atributo |
formulario_rep | Formulario T | subtítulo | informe dinámico |
Rep rápida | TQuickRep | Conjunto de datos | REP_QUERY |
DetalleBanda1 | Banda TQRB | Tipo de banda | rbDetalle |
ColumnaEncabezadoBanda1 | Banda TQRB | Tipo de banda | rbColumnEncabezado |
REP_Fuente de datos | Fuente de datos T | Conjunto de datos | Rep_Query |
Rep_Query | TQuery | Nombre de la base de datos | REPDATABASE |
Base de datos_representante | Base de datos T | Conectado | Verdadero |
Params.Strings | 'NOMBRE DEL SERVIDOR=XXX 'USUARIO MAME=XXX' 'CONTRASEÑA=XXX' | ||
Nombre de la base de datos | REPDATABASE |
Los controles que se muestran en la tabla anterior se crearon manualmente en el programa. Otros controles deben crearse dinámicamente en el programa.
2.2.2 Procedimientos principales
unidad f_rep;
interfaz
usos
Windows, Mensajes, SysUtils, Variantes, Clases, Gráficos, Controles, Formularios,
Diálogos, ExtCtrls, QuickRpt, QRCtrls, DB, DBTables, IMPRESORAS, QRPrntr, infiles,
TeeProcs, TeEngine, DbChart, QRTEE;
tipo
TForm_rep = clase(TForm)
QuickRep: TQuickRep;
DetalleBanda1: TQRBand;
ColumnHeaderBand1: TQRBand;
REP_DataSource: TDataSource;
REP_QUERY: TQuery;
rep_Database: TDatabase;
procedimiento TForm_rep.QuickRepAfterPreview(Sender: TObject);//Después de navegar, libere todos los componentes creados
privado
{Declaraciones privadas}
público
{Declaraciones públicas}
fin;
var Form_rep:TForm_Rep;
tipo //Información resumida del informe
C_rep_Summary=registro
Título:cadena;//El título del informe
Page:TQRPaperSize;//La configuración de página del informe, qué tipo de papel se utiliza
Orientación:TPrinterOrientation;//La configuración de página del informe, ya sea horizontal o vertical
Columns:integer;//Número de columnas incluidas en el informe
fin;
tipo
C_Rep_Col_Summary=record//Información resumida de las columnas del informe
Caption:string;//nombre de columna del informe
DataFiled:string;//El nombre del campo en la base de datos correspondiente a la columna del informe
Ancho: entero; // ancho de columna del informe
fin;
tipo
C_Rep_Col_Sum_store=record //Almacenamiento de información resumida de las columnas del informe
Caption_array:matriz de cuerdas;
DataFiled_array:matriz de cadena;
width_array:matriz de números enteros;
fin;
var
rep_Summary:C_rep_Summary;
Rep_Col_Summary:C_Rep_Col_Summary;
Rep_Col_Sum_store:C_Rep_Col_Sum_store;
Colum_Name: matriz de tQRRichText;
Colum_Data:matriz de TQRDBRichText;
C_Query: TQuery;
procedimiento Form_rep_init();
procedimiento DynCreat_TQRDBText(Colum_Num:integer;Colum_Height:integer;DataSet_Name:TQuery);//Crear dinámicamente el control TQRDBText
procedimiento DynCreat_TQRRichtext(Colum_Num:integer);//Crear dinámicamente el control TQRRichtext
procedimiento DynCreat_TQuery(Inifile_Name:Tinifile);//Instrucción SQL para crear dinámicamente el control TQuery
procedimiento Get_PageCount();//Obtener el número total de páginas impresas
función Open_IniFile():Tinifile;//Abrir archivo temporal
procedimiento Read_Col_Summary(Inifile_Name:Tinifile);//Leer información resumida de las columnas del informe
procedimiento Read_Rep_Summary(Inifile_Name:Tinifile);//Leer información resumida del informe
función rep_chanslateOrientation(var Rep_Orientation:integer):TPrinterOrientation;//Convierte la configuración del modo de impresión
función rep_chanslatepage(var Rep_Page:integer):TQRPaperSize;//Convierte la configuración del tamaño de la página de impresión
implementación
{$R*.dfm}
función rep_chanslatepage(var Rep_Page:integer):TQRPaperSize;//Convierte la configuración del tipo de página de impresión
comenzar
caso Rep_Página de
1:comenzar
resultado:=A4;
Form_rep.QuickRep.PrinterSettings.PaperSize:=A4;
fin;
2:comenzar
resultado:=B5;
Form_rep.QuickRep.PrinterSettings.PaperSize:=B5
fin;
3:comenzar
resultado:=Ejecutivo;
Form_rep.QuickRep.PrinterSettings.PaperSize:=Ejecutivo;
fin;
fin;
fin;
función rep_chanslateOrientation(var Rep_Orientation:integer):TPrinterOrientation;//Convierte la configuración del modo de impresión
comenzar
caso Rep_Orientation de
0:comenzar
resultado:=poPortrait;//0 es vertical
Form_rep.QuickRep.PrinterSettings.Orientation:=poPortrait;
fin;
1:comenzar
resultado:=poLandscape;//1 es horizontal
Form_rep.QuickRep.PrinterSettings.Orientation:=poLandscape;
fin;
fin;
fin;
función Open_IniFile():Tinifile;//Abrir archivo temporal
var Nombre de archivo: cadena;
Ini_Filename:cadena;
comenzar
Nombre de archivo:='Report.ini';
Ini_Filename:=File_Path+Nombre de archivo;
Resultado:=Tinifile.Create(Ini_Filename);
fin;
procedimiento Read_Rep_Summary(Inifile_Name:Tinifile);//Leer información resumida del informe
var Rep_Page,Rep_Orientation: entero;
comenzar
rep_Page:=Inifile_Name.Readinteger('rep_detail','Page',1);
Rep_Orientation:=Inifile_Name.Readinteger('rep_detail','Orientation',0);
con rep_Summary hacer
comenzar
Columnas:=Inifile_Name.Readinteger('rep_detail','columns',0);
Título:=Inifile_Name.Readstring('rep_detail','Título','Informe sin nombre');
page:=rep_chanslatepage(Rep_Page);//Convierte el tamaño de la página de impresión
Orientation:=rep_chanslateOrientation(Rep_Orientation);//Convierte la configuración del modo de impresión
fin;
fin;
procedimiento Read_Col_Summary(Inifile_Name:Tinifile);//Leer información resumida de las columnas del informe
var i_count: entero;
comenzar
//Guardar información de la columna en una matriz
con Rep_Col_Sum_store hacer
comenzar
SetLength(Caption_array,rep_Summary.Columns);
SetLength(DataFiled_array,rep_Summary.Columns);
SetLength(Width_array,rep_Summary.Columns);
fin;
para i_count:=0 a rep_Summary.Columns-1 hacer
comenzar
con Rep_Col_Summary hacer
comenzar
Título:=Inifile_Name.Readstring('col_'+inttostr(i_count),'Caption','Sin nombre');
DataFiled:=Inifile_Name.Readstring('col_'+inttostr(i_count),'DataFiled','');
Ancho:=Inifile_Name.Readinteger('col_'+inttostr(i_count),'Ancho',0);
fin;
con Rep_Col_Sum_store hacer
comenzar
Caption_array[i_count]:=Rep_Col_Summary.Caption;
DataFiled_array[i_count]:=Rep_Col_Summary.DataFiled;
Ancho_array[i_count]:=Rep_Col_Summary.Width;
fin;
fin;
fin;
procedimiento DynCreat_TQRRichtext(Colum_Num:integer);// Crea dinámicamente un control TQRRichtext, que se utiliza para mostrar el nombre chino de cada columna en el informe.
var Colum_Name_list:TStrings;
comenzar
Colum_Name[Colum_Num]:=tQRRichtext.Create(aplicación); //Crear control TQRRichtext;
Nombre_columna[Núm_columna].Parent:=Form_rep.ColumnHeaderBand1;
Nombre_columna[Núm_columna].Frame.DrawTop:=true;
Nombre_columna[Núm_columna].Frame.DrawBottom:=true;
Form_rep.ColumnHeaderBand1.Height:=40;
Nombre_columna[Núm_columna].Altura:=40;
Nombre_columna[Núm_columna].Font.Height:=-14;
Colum_Name[Colum_Num].Font.Name:='Cuerpo del infierno';
Nombre_columna[Núm_columna].Arriba:=0;
Nombre_columna[Núm_columna].Alineación:=taCenter;
Nombre_columna[Núm_columna].AutoStretch:=false;
//Dibujar líneas de tabla
Nombre_columna[Núm_columna].Frame.Style:=psSolid;
Nombre_columna[Núm_columna].Frame.Width:=1;
Nombre_columna[Núm_columna].Frame.DrawRight:=true;
Nombre_columna[Núm_columna].Frame.DrawBottom:=true;
si Colum_Num=0 entonces
comenzar
Nombre_columna[Núm_columna].Frame.DrawLeft:=true;
fin;
//Asigna la información del registro RRep_Col_Sum_store a Colum_Name
Colum_Name_list:=TStringList.Create;
Colum_Name_list.Add(Rep_Col_Sum_store.Caption_array[Colum_Num]);
Nombre_columna[Num_columna].Lineas:=Lista_nombre_columna;
Nombre_columna[Num_columna].Ancho:=Rep_Col_Sum_store.Width_array[Num_columna];
Nombre_columna[Núm_columna].Visible:=verdadero;
//Calcular el límite izquierdo
si Colum_Num>0 entonces
Nombre_Columna[Num_Columna].Izquierda:=Nombre_Columna[Num_Columna-1].Izquierda+Nombre_Columna[Num_Columna-1].Ancho
demás
Nombre_columna[Núm_columna].Izquierda:=0;
fin;
Nota: El control TQRRichtext se utiliza aquí porque el control TQRRichtext puede ajustar líneas automáticamente cuando el nombre es demasiado largo.
procedimiento DynCreat_TQRDBText(Colum_Num:integer;Colum_Height:integer;DataSet_Name:TQuery);//Crea dinámicamente un control TQRDBText, que se utiliza para mostrar el valor de cada columna
comenzar
Colum_Data[Colum_Num]:=tQRDBText.Create(aplicación);
Colum_Data[Colum_Num].Parent:=Form_rep.DetailBand1;
//Establece el conjunto de datos
Colum_Data[Colum_Num].DataSet:=DataSet_Name;
//Establece la propiedad de la matriz Colum_Data.DateField en el nombre del campo en 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].Altura:=Colum_Height;
Form_rep.DetailBand1.Height:=Colum_Height;
Colum_Data[Colum_Num].Arriba:=0;
Colum_Data[Colum_Num].AutoSize:=false;
Colum_Data[Colum_Num].AutoStretch:=false;
Colum_Data[Colum_Num].WordWrap:=false;
Colum_Data[Colum_Num].Visible:=verdadero;
//Dibujar líneas de tabla
Colum_Data[Colum_Num].Frame.Style:=psSolid;
Colum_Data[Colum_Num].Frame.DrawRight:=true;
Colum_Data[Colum_Num].Frame.DrawBottom:=true;
si Colum_Num=0 entonces
Colum_Data[Colum_Num].Frame.DrawLeft:=true;
//Calcular el límite izquierdo
si Colum_Num>0 entonces
Colum_Data[Colum_Num].Left:=Colum_Data[Colum_Num-1].Left+Colum_Data[Colum_Num-1].Ancho
demás
Colum_Data[Colum_Num].Izquierda:=0;
fin;
procedimiento DynCreat_TQuery(Inifile_Name:Tinifile);//Establece dinámicamente la declaración SQL del control TQuery
var
Sql_command:cadena;
comenzar
Flag_CreatQuery:=falso;
Sql_command:=Inifile_Name.Readstring('QureyData','Sql_Command','');
Form_rep.REP_QUERY.Cerrar;
Form_rep.REP_QUERY.SQL.Clear;
Form_rep.REP_QUERY.SQL.Append(Sql_command);
si no Form_rep.REP_QUERY.Prepared entonces
Form_rep.REP_QUERY.Preparar;
intentar
Form_rep.REP_QUERY.ExecSQL;
Form_rep.REP_QUERY.Active:=verdadero;
Form_rep.REP_QUERY.AutoCalcFields:=verdadero;
Flag_CreatQuery:=verdadero;
excepto
Application.MessageBox('¡Error en la declaración SQL!','Mensaje del sistema',MB_ICONWARNING);
Flag_CreatQuery:=falso;
fin;
fin;
procedimiento Form_rep_init();
var i_count: entero;
Rep_IniFile:Tinifile;//