Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Impresión
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 24-12-2003
Avatar de sitrico
[sitrico] sitrico is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Caracas, Venezuela
Posts: 295
Poder: 22
sitrico Va por buen camino
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
Responder Con Cita
  #2  
Antiguo 24-12-2003
Descendents Descendents is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona
Posts: 396
Poder: 22
Descendents Va por buen camino
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
Responder Con Cita
  #3  
Antiguo 24-12-2003
__cadetill __cadetill is offline
Miembro
 
Registrado: may 2003
Posts: 3.387
Poder: 25
__cadetill Va por buen camino
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;
........
de esta manera, en el momento de liberar la memoria, sólo hay que recorrer el array haviendo un free de cada posición.
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
Responder Con Cita
  #4  
Antiguo 26-12-2003
Avatar de sitrico
[sitrico] sitrico is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Caracas, Venezuela
Posts: 295
Poder: 22
sitrico Va por buen camino
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;
Para crear el reporte uso
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;
y aun así no se completa el free del reporte (pese al finally)

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;
Si alguien sabe que ocurre, agradezco cualquier sugerencia.

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
Responder Con Cita
  #5  
Antiguo 26-12-2003
Avatar de delphi.com.ar
delphi.com.ar delphi.com.ar is offline
Federico Firenze
 
Registrado: may 2003
Ubicación: Buenos Aires, Argentina *
Posts: 5.932
Poder: 27
delphi.com.ar Va por buen camino
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.
Responder Con Cita
  #6  
Antiguo 26-12-2003
Avatar de sitrico
[sitrico] sitrico is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Caracas, Venezuela
Posts: 295
Poder: 22
sitrico Va por buen camino
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.
Responder Con Cita
  #7  
Antiguo 26-12-2003
Avatar de sitrico
[sitrico] sitrico is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Caracas, Venezuela
Posts: 295
Poder: 22
sitrico Va por buen camino
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);
Sobra el -1 ya que se nececitan "Count" elementos, la declaración correcta es:

Código:
SetLength(lbs,fSa3700.DBGridArancel.Columns.Count);
SetLength(fld,fSa3700.DBGridArancel.Columns.Count);
Adicionalmente encontre otros errores (menores), el valor de Width podia ser negativo (0-sep) = 0-5 = -5 y el evento AfterPrint y AfterPreview deben asignarse al procedimiento ReporteAfterPrint.

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.
Responder Con Cita
  #8  
Antiguo 04-01-2004
fjcg01 fjcg01 is offline
Registrado
 
Registrado: jun 2003
Ubicación: Barakaldo
Posts: 4
Poder: 0
fjcg01 Va por buen camino
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.
Responder Con Cita
  #9  
Antiguo 05-01-2004
fjcg01 fjcg01 is offline
Registrado
 
Registrado: jun 2003
Ubicación: Barakaldo
Posts: 4
Poder: 0
fjcg01 Va por buen camino
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
Responder Con Cita
  #10  
Antiguo 07-01-2004
Avatar de fjcg02
[fjcg02] fjcg02 is offline
Miembro Premium
 
Registrado: dic 2003
Ubicación: Zamudio
Posts: 1.410
Poder: 22
fjcg02 Va camino a la fama
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.
Responder Con Cita
  #11  
Antiguo 10-01-2004
ramiretor ramiretor is offline
Miembro
 
Registrado: may 2003
Ubicación: México
Posts: 196
Poder: 22
ramiretor Va por buen camino
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.
Responder Con Cita
  #12  
Antiguo 10-01-2004
__cadetill __cadetill is offline
Miembro
 
Registrado: may 2003
Posts: 3.387
Poder: 25
__cadetill Va por buen camino
no se si te he entendido, pero si es un array dinámico, puedes establecer su longitud a 0 con Setlength
Responder Con Cita
  #13  
Antiguo 12-01-2004
ramiretor ramiretor is offline
Miembro
 
Registrado: may 2003
Ubicación: México
Posts: 196
Poder: 22
ramiretor Va por buen camino
Hola:
Gracias por responder efectivamente, me entendiste y esa era la respuesta que esperaba oir.

Un saludo

__________________
Ernesto R.
Responder Con Cita
  #14  
Antiguo 14-01-2004
Avatar de sitrico
[sitrico] sitrico is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Caracas, Venezuela
Posts: 295
Poder: 22
sitrico Va por buen camino
Tuve la misma duda, pero yo liberé el array con finalize(TArray). ¿es lo mismo que SetLenght(0)?

Saludos
__________________
Sitrico
Responder Con Cita
  #15  
Antiguo 15-01-2004
__cadetill __cadetill is offline
Miembro
 
Registrado: may 2003
Posts: 3.387
Poder: 25
__cadetill Va por buen camino
Pues no estoy seguro, pero según dice la ayuda, también puede utilizarse

Cita:
Dynamic arrays can never be deallocated using the Dispose procedure, but can be freed by passing them to Finalize.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro


La franja horaria es GMT +2. Ahora son las 17:50:13.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi