FTP | CCD | Buscar | Trucos | Trabajo | Foros |
|
Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Temas de Hoy |
|
Herramientas | Buscar en Tema | Desplegado |
#1
|
||||
|
||||
Crear las columnas en Runtime (QReport)
Primero lo primero: Felices Fiestas.
Ya entrando en materia: necesito crear en runtime las columnas de un reporte qReport (QRDBText) y sus titulos asociados (QRDBLabel) en tiempo de ejecución. (Cada uno está en su QRBand respectivo). La intención es poder imprimir una BDD (Paradox) que se muestra en un DBGrid, el usuario puede escojer entre las diferentes BDD del sistema para consultarlas y la intención es crear un reporte generico que incluya todos (o algunos) de los campos de la BDD consultada para generar el reporte. Lo que necesito es un ciclo mas o menos: For i := 0 to DBGrid.Colums.count-1 do c := tQRDBText.Create(Self); c.Top,Left,Width... // Asignar posicion y tamaño c.DataSet, FieldName... // Asignar Tabla y campo Como asigno el nuevo objeto al Band? ¿AddPrintable? c.free???? // se debe liberar antes de crear el otro? End; Creo que es más o menos lo que se debe hacer pero en las pruebas que he realizado no logro asignar el objeto a la banda del reporte correspondiente. Gracias por su ayuda.
__________________
Sitrico |
#2
|
|||
|
|||
Yo con quick reports creo que se puede hacer todo.Incluso he hecho algunas veces quickreports enteros por codigo.Te recomiendo en casos dificiles hacer lo que haces.
Vas bien encaminado, pero te falta el parent. ejemplo: c.parent := detailband1; Saludos |
#3
|
|||
|
|||
a parte de lo mencianado por Descendents, cuando tengo que hacer reportes de esta manera, lo que hago es declarar arrays de los componentes que necesito
Código:
var Labels : array of TQrLabel; Labels : array of TQrDBText; ........ La destrucción depende de como montes el reporte. Personalmente tengo la manía de declarar un procedimiento público (public) al cual llamo y es el encargado de hacer todo el trabajo sucio (creación de objetos, lanzar SQLs, crear temporales,.....), lanzar el reporte (Print o Preview) y, si se da el caso, liberar objetos creados Espero que la idea te guste |
#4
|
||||
|
||||
Gracias por la ayuda, ya logre crear y generar el reporte, pero ahora tengo el problema que al cerrar el reporte se me genera una "Operación de Puntero Invalida" y el reporte no se destruye apropiadamente. (El Reporte está construido en un TQuickRep no en un TForm)
Aqui está el Código en cuestión: Código:
procedure TfSA3710.QuickRepBeforePrint(Sender: TCustomQuickRep; var PrintReport: Boolean); Var fCons : TfSA1000; Begin FCons := TfSA1000(fSA0000.ActiveMDIChild); dba.TableName := fCons.dbArancel.TableName; CrearColumnas; dbA.Open; end; procedure TfSA3710.QuickRepAfterPrint(Sender: TObject); Var i : Integer; begin // For i := 0 to fSa3700.DBGridArancel.Columns.Count-1 do // Begin // lbs[i].Free; // fld[i].Free; // End; For i := SizeOf(lbs) DownTo 0 do lbs[i].Free; For i := SizeOf(fld) DownTo 0 do fld[i].Free; dbA.Close; end; procedure TfSA3710.CrearColumnas; Const Sep = 5; Var i,px,ATot,Ancho : Integer; begin aTot := 0; For i := 0 to fSa3700.DBGridArancel.Columns.Count-1 do ATot := ATot + fSa3700.DBGridArancel.Columns.Items[i].Width; px := 0; // Definir el tamaño del Array; SetLength(lbs,fSa3700.DBGridArancel.Columns.Count-1); SetLength(fld,fSa3700.DBGridArancel.Columns.Count-1); For i := 0 to fSa3700.DBGridArancel.Columns.Count-1 do Begin Ancho :=(Titulos.Width * fSa3700.DBGridArancel.Columns.Items[i].Width) div ATot; // Encabezados lbs[i] := TQRLabel.Create(Titulos); With lbs[i] do Begin Parent := Titulos; Top := 1; Left := px; AutoSize := False; Width := Ancho - Sep; Visible := fSa3700.DBGridArancel.Columns.Items[i].Visible; If Visible Then begin Alignment := fSa3700.DBGridArancel.Columns.Items[i].Alignment; Caption := fSa3700.DBGridArancel.Columns.Items[i].Title.Caption; End; End; // Campos fld[i] := TQRDBText.Create(detalle); With Fld[i] do begin Parent := Detalle; Top := 1; Left := px; AutoSize := False; Width := Ancho - Sep; Visible := lbs[i].Visible; If Visible Then Begin Alignment := lbs[i].Alignment; DataSet := dbA; DataField := fSa3700.DBGridArancel.Columns.Items[i].FieldName; WordWrap := True; AutoStretch := True; End; End; // Posicion X del proximo px := px + Ancho; End; end; Código:
Var Rep : TFsa3710; begin Rep := TFsa3710.Create(Self); Try rep.PrinterSetup; If rep.Tag = 0 then rep.Preview; // rep.Print; Finally rep.Free; End; end; Las declaraciones de los arreglos y el metodo crear columnas las puse como publicas y privadas. Código:
lbs : Array of TQRLabel; fld : Array of TQRDBText; Procedure CrearColumnas; PD Uso delphi 7 con QReport 3.5.1 (descargado de QuSoft) el error me lo genera en la unidad System Código:
function _FreeMem(P: Pointer): Integer; {$IF Defined(DEBUG) and Defined(LINUX)} var Signature: PLongInt; {$IFEND} begin if P <> nil then begin {$IF Defined(DEBUG) and Defined(LINUX)} Signature := PLongInt(LongInt(P) - 4); if Signature^ <> 0 then Error(reInvalidPtr); Signature^ := FreeMemorySignature; Result := MemoryManager.Freemem(Pointer(Signature)); {$ELSE} Result := MemoryManager.FreeMem(P); {$IFEND} if Result <> 0 then Error(reInvalidPtr); // <- - - - - - - - - - - - Linea de error end else Result := 0; end;
__________________
Sitrico |
#5
|
||||
|
||||
Puedo sugerirte que pruebes el QueryPrint, es un componente hecho con este propósito, puedes bajarlo de mi página.
Saludos!
__________________
delphi.com.ar Dedique el tiempo suficiente para formular su pregunta si pretende que alguien dedique su tiempo en contestarla. |
#6
|
||||
|
||||
No quiero despreciar el ofrecimiento de delphi.com.ar pero creo que lo que me falta es una tonteria, de todas maneras voy a ver el componente como ejemplo (aunque trabajo con tablas). además, debe haber otra manera de correjir un error que no sea bajar un componente de delphi.com.ar o de catedetill* ;-)
Saludos y gracias * o de cualquier otro participante que haya aportado componentes.
__________________
Sitrico Última edición por sitrico fecha: 26-12-2003 a las 19:32:33. |
#7
|
||||
|
||||
Como dicen: "El que persevera alcanza", el error estaba en la asignación del tamaño del array:
Código:
SetLength(lbs,fSa3700.DBGridArancel.Columns.Count-1); SetLength(fld,fSa3700.DBGridArancel.Columns.Count-1); Código:
SetLength(lbs,fSa3700.DBGridArancel.Columns.Count); SetLength(fld,fSa3700.DBGridArancel.Columns.Count); Con estas correciones se logra imprimir el DBGrid con una ancho de columnas proporcional al de pantalla. Gracias a todos por su ayuda.
__________________
Sitrico Última edición por sitrico fecha: 26-12-2003 a las 20:20:25. |
#8
|
|||
|
|||
Hola a todos,
fusilando por ahí fusilando por allá, he tomado de base este hilo para hacer una nueva versión de un generador de reportes que tenía hecho en Ace report y que el Delphi 7 no funciona - o yo por lo menos no he conseguido instalar los componentes ACE -. Adjunto el código de llamada al form, que lo genera y prepara las propiedades de los objetos, que son los siguientes: - Query que quieres imprimir - DBGrid idem - Titulo, empresa y condiciones son strings que se escriben el la cabecera. - VisualizarTotales es un string con los nombres de los campos separados con comas - o sin separa, para que nos vamos a engañar - que queremos totalizar - GrupoTotales es un string con los nombres de los campos que si cambia alguno de ellos se imprime la banda de totales. Mi problema se plantea cuando ejecuto el informe. A veces se imprime OK, pero otras veces, en la banda de los totales no aparecen los mismos. Como podeis ver, hay cuatro bandas, Cabecera de reporte, cabecera de grupo, detalle, pie de grupo y pie de reporte. Si alguien me puede ayudar, pues lo agradecería mucho, ya que estoy pegándome un poquito con ello y ya me sale humo de la cabeza. ------------------------------------------------------------- :: Funcion de generar listados a partir de un Grid automáticamente :: :: Forma de llamarlo :: :: GenerarListado( Query que queremos imprimir ADO :: :: Grid asociado a la query :: :: Titulo del Listado :: :: empresa del listado :: :: Condiciones del listado ( literal) :: :: Campos que queremos sumar separados por comas :: :: Campos que cuando cambian se imprimen los totales:: :: separados por comas :: :: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: } unit mdrpt; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, QuickRpt, Qrctrls, Db, DBTables, ExtCtrls,Grids, DBGrids,ADODB,printers; type TFrmQuick = class(TForm) QuickRep1: TQuickRep; PageHeaderBand1: TQRBand; QRLTitulo: TQRLabel; QRLEmpresa: TQRLabel; QRLCondiciones: TQRLabel; QRSysData1: TQRSysData; QRShape1: TQRShape; QRGroup1: TQRGroup; DetailBand1: TQRSubDetail; GroupFooterBand1: TQRBand; QRBand1: TQRBand; QRLabelP: TQRLabel; QRSysData3: TQRSysData; QRShape2: TQRShape; QRLabel1: TQRLabel; QRLabel2: TQRLabel; QRShape3: TQRShape; procedure QuickRep1AfterPrint(Sender: TObject); private { Private declarations } procedure PrepararListado(Query:TADOQuery; DBGRid: TDBGrid; VisualizarTotales,GrupoTotales:string); public { Public declarations } Titulos: array of TQrLabel; Campos: array of TQRDBText; Totales: array of TQrExpr; function GenerarListado( Query:TADOQuery; DBGrid: TDBGrid; Titulo,empresa,Condiciones,VisualizarTotales,GrupoTotales: string): boolean; end; var FrmQuick: TFrmQuick; implementation {$R *.dfm} function TFrmQuick.GenerarListado( Query:TADOQuery; DBGrid: TDBGrid; Titulo,empresa,Condiciones,VisualizarTotales,GrupoTotales: string): boolean; var Mibookmark: string ; begin Try Application.CreateForm(TFrmQuick, FrmQuick); with FrmQuick do begin QRLEmpresa.Caption:= Empresa; QRLCondiciones.Caption:=condiciones; QRLTitulo.Caption:=Titulo; MiBookmark:=Query.Bookmark; QuickRep1.Dataset:= Query; DetailBand1.Dataset:= Query; PrepararListado (Query,DBGrid,VisualizarTotales,GrupoTotales); QuickRep1.PreviewModal; Query.Bookmark:= MiBookMark; end; finally FrmQuick.Free; end; GenerarListado:=True end; procedure TFrmQuick.PrepararListado(Query:TADOQuery;DBGRid: TDBGrid; VisualizarTotales,GrupoTotales:string); const Sep=2; var n, px:integer; begin px:=Sep; // definir tamaño del array SetLength(Titulos, DBGrid.Columns.Count); SetLength(Campos, DBGrid.Columns.Count); SetLength(Totales, DBGrid.Columns.Count); QRGroup1.Height:= 0; // para que no se visualice if VisualizarTotales='' then GroupFooterBand1.Height:= 0; for n:= 0 to DBGrid.Columns.count-1 do begin // titulos Titulos[n]:= TQRLabel.Create(PageHeaderBand1); with Titulos[n] do begin parent:= PageHeaderBand1; Top:= PageHeaderBand1.Height-25; Left:= px; AutoSize:= False; Width:= DBGrid.Columns.Items[n].Width; Alignment:=DBGrid.Columns.Items[n].Alignment; Caption:= DBGrid.Columns.Items[n].Title.Caption; Font.Size:= DBGrid.Font.Size; // Font.Style:=[fsBold]; end; // Grupo de ruptura para los totales if pos( DBGrid.Columns.Items[n].Title.Caption, GrupoTotales) > 0 then begin if QRGroup1.Expression='' then QRGroup1.Expression:=DBGrid.Columns.Items[n].fieldname else QRGroup1.Expression:=DBGrid.Columns.Items[n].fieldname; end; // Campos para visualizar Totales if pos( DBGrid.Columns.Items[n].Title.Caption, VisualizarTotales) > 0 then begin totales[n]:=TQRExpr.Create(GroupFooterBand1); with Totales[n] do begin parent:= GroupFooterBand1; Top:= 5; Left:= px; AutoSize:= False; Width:= DBGrid.Columns.Items[n].Width; Alignment:=DBGrid.Columns.Items[n].Alignment; Master:= DetailBand1; Mask:= '#,###,###'; Expression:= 'SUM('+DBGrid.Columns.Items[n].fieldname+')'; Font.Size:= DBGrid.Font.Size;ResetAfterPrint:= True; end; end; // Campos Campos[n]:= TQRDBText.Create(DetailBand1); with Campos[n] do begin parent:= DetailBand1; Top:= 0; Left:= px; AutoSize:= False; Width:= DBGrid.Columns.Items[n].Width; Alignment:=DBGrid.Columns.Items[n].Alignment; Dataset:= Query; Datafield:= DBGrid.Columns.Items[n].FieldName; WordWrap:= True; Autostretch:= True; Font.Size:= DBGrid.Font.Size; end; px:= px +DBGrid.Columns.Items[n].Width + sep; end; // Orientacion de la page dependiendo de los campos if px >= 695 then begin QuickRep1.Page.Orientation:= poLandscape; // apaisado QRShape1.Width:= 1027; QRShape2.Width:= 1027; QRShape3.Width:= 1027; QRLTitulo.Width:= 1027; QRSysData1.Left:= 1027 - QRSysData1.Width; QRLabelP.Left:= 450; QRSysData3.Left:= 500; end else QuickRep1.Page.Orientation:= poPortrait; end; procedure TFrmQuick.QuickRep1AfterPrint(Sender: TObject); var n:integer; begin for n:= sizeof(Titulos) downto 0 do Titulos[n].Free; for n:= sizeof(Campos) downto 0 do Campos[n].Free; for n:= sizeof(Campos) downto 0 do totales[n].Free; end; end. |
#9
|
|||
|
|||
Hola a todos,
estoy flipando un poquito, ya que la dificultad que tenia este metodo es que cuando le paso una consulta con transform de fechas TRANSFORM Sum(Importe) AS SumaDeImporte SELECT Vendedor FROM Presupue where Fecha>= #01/01/03# and Fecha<= #31/12/03# GROUP BY Vendedor PIVOT Format(Fecha,'MM-MMM') ** pongo este formato para que me numere los meses, de manera que me aparezcan 01-ene, 02-feb. Si no lo hago así, los meses me aparecen en orden alfabetico, es decir, abril, agosto, diciembre, ... ** y los campos que quiero totalizar son '01-ene,02-feb,03-mar, .....' Cuando construyo la banda de los totales, el quickReport se vuelve loco porque la expresion queda SUM(01-ene), lo que no le gusta y no me saca los totales. Sin embargo si le pongo el formato MMMM y le paso para totalizar 'enero, febrero, marzo, ...' , me los totaliza sin problemas ¿ Podría alguien echarme una mano ? Gracias por vuestra colaboración. Un saludo |
#10
|
||||
|
||||
La respuesta is blowing in the wind
Gracias a todos los que habeis perdido vuestro tiempo, pero ya se la solución. Por motivos deconocidos, el quickreport no suma los campos en los que su nombre mezcla numeros y letras. Para solventar el problema, utilizo PIVOT FORMAT(Fecha,'MMMM') in (enero, febrero, marzo, ....). De esta manera, me salen las columnas ordenadas tal y como las he escrito, no mezclo numeros y letras y el quickrepot saca todo lo que tiene que sacar. Un saludo y gracias.
__________________
Cuando los grillos cantan, es que es de noche - viejo proverbio chino - Última edición por fjcg02 fecha: 22-01-2004 a las 13:31:44. |
#11
|
|||
|
|||
Hola:
Una ultima pregunta, ustedes que saben mucho más que yo, imaginemos que tenemos el Array de TQRDBText lo llamaremos Campos y creamos todo el arreglo en ejecucion, citrico puso una rutina parecida a esta, para liberarlo de la memoria: for i:= o to NumeroCampos do begin Campos[i].Free; end; donde i es un acumulador y NumeroCampos es los campos que se generaron... Bueno la pregunta es que se van liberando los elementos de Campos uno a uno pero ¿será posible que el Array se quede con los elementos nulos?, es decir si se generaron por ejemplo 10 columnas no se quedarán diez ( hablando en términos de matrices) columnas nulas? Saludos y muchas gracias por escuchar
__________________
Ernesto R. |
#12
|
|||
|
|||
no se si te he entendido, pero si es un array dinámico, puedes establecer su longitud a 0 con Setlength
|
#13
|
|||
|
|||
Hola:
Gracias por responder efectivamente, me entendiste y esa era la respuesta que esperaba oir. Un saludo
__________________
Ernesto R. |
#14
|
||||
|
||||
Tuve la misma duda, pero yo liberé el array con finalize(TArray). ¿es lo mismo que SetLenght(0)?
Saludos
__________________
Sitrico |
#15
|
|||
|
|||
Pues no estoy seguro, pero según dice la ayuda, también puede utilizarse
Cita:
|
|
|
|