 |
Club Builder Foro de C++Builder en español
|
| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
bosoft Master

Registrado: 23 Oct 2005Mensajes: 342
|
Publicado: Dom 17 Ene, 2010 7:50 pm Asunto: imprimir listview |
|
|
Ya se que se ha preguntado varias veces, pero ninguna tiene la solución definitiva.
Mirando por internet, he encontrado esta página y sobre todo la clase printobj (http://www.marteens.com/ejemplos.htm) pero está en delphi. Parece interesante, pero no llego a acabar de traducir el código, sobre todo | Código: | FStarts: array of Integer;
FWidths: array of Integer;
SetLength(FStarts, FListView.Columns.Count);
SetLength(FWidths, FListView.Columns.Count);
for I := Low(FStarts) to High(FStarts) do
|
Lo interesante está en que le mandas el listview a imprimir y no importa las columnas que tenga
Espero vuestra ayuda para poder hacer algo parecido en C++, ya que no estoy muy fuerte en programar clases
la llamada la hago así, segun pone la explicación de la página
| Código: | if(!PrintDialog1->Execute()) return;
TPrintObj *prn = new TPrintObj();
prn->Create(Printer(),ListView1);
prn->ListPrint("","");
prn->Destroy();
|
Saludos, Bosoft
PD: si queréis la traducción que he hecho, os la pego. Y el programa tiene un fallo si lo compilo en mi proyecto y no puedo detectarlo, porque builder 2007 no me hace el seguimiento dentro del .pas |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Lun 18 Ene, 2010 12:59 am Asunto: |
|
|
No he mirado el código original, cuando tenga tiempo lo haré. Te adelanto que en delphi los arrays pueden ser estáticos o dinámicos. En el código que expones se refiere a arrays dinámicos, de forma que
| Código: | FStarts: array of Integer;
//es equiparable a:
int *FStarts;
|
y
| Código: | SetLength(FStarts, FListView.Columns.Count);
// asigna el tamaño del array dinámico y podría traducirse como
FStarts = new int[FListView.Columns.Count]; |
En delphi no se destruyen explicitamente estos arrays, desaparecen o liberan automáticamente al salir del ambito. En C++ debes destruirlos con | Código: | delete [] FStarts; |
Por ultimo el bucle que pones en la sentencia for, se refiere a un bucle que comienza en el primer elemento del array y termina en el último. Podrías poner algo como:
| Código: | for(int i=0; i<FListView.Columns.Count; i++){
.................
} |
Saludos. |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Lun 18 Ene, 2010 12:55 pm Asunto: |
|
|
He mirado el código. Te propongo esta traducción:
PrintObject.h
| Código: | //---------------------------------------------------------------------------
#ifndef PrintObjectH
#define PrintObjectH
//---------------------------------------------------------------------------
#include <printers.hpp>
#include <ComCtrls.hpp>
class TPrintObj
{
protected:
TPrinter *FPrinter;
String FTitle;
String FPageFormat;
TListView *FListView;
int FCurY;
int FMaxX;
int FMaxY;
int FHeight;
int *FStarts;
int *FWidths;
void NewLine();
void PrintHeader();
void PrintLine(TListItem *AItem);
void PrintRect(const String S, int Column);
public:
TPrintObj(TPrinter *APrinter, TListView *AListView);
~TPrintObj();
void Print(const String ATitle = "", const String APageFormat = "");
};
#endif
|
PrintObject.cpp:
| Código: | //---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "PrintObject.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
TPrintObj::TPrintObj(TPrinter *APrinter, TListView *AListView)
{
FPrinter = APrinter;
FListView = AListView;
FStarts = 0;
FWidths = 0;
}
TPrintObj::~TPrintObj()
{
if(FStarts) delete [] FStarts;
if(FWidths) delete [] FWidths;
}
void TPrintObj::NewLine()
{
FCurY += FHeight;
if (FCurY > FMaxY - 2 * FHeight){
FCurY = 0;
FPrinter->NewPage();
}
}
void TPrintObj::Print(const String ATitle, const String APageFormat)
{
int I, FConvX1, FConvX2;
FPrinter->BeginDoc();
__try{
FPrinter->Canvas->Font->Assign(FListView->Font);
FTitle = ATitle;
FPageFormat = APageFormat;
FCurY = 0;
FMaxX = FPrinter->PageWidth;
FMaxY = FPrinter->PageHeight;
FConvX1 = FPrinter->Canvas->TextWidth("M");
FConvX2 = FListView->Canvas->TextWidth("M");
if(FStarts) delete [] FStarts;
FStarts = new int[FListView->Columns->Count];
if(FWidths) delete [] FWidths;
FWidths = new int[FListView->Columns->Count];
for (int I = 0; I < FListView->Columns->Count; I++){
if(I == 0)
FStarts[I] = FConvX1;
else
FStarts[I] = FStarts[I - 1] + FWidths[I - 1];
FWidths[I] = FListView->Columns->Items[I]->Width * FConvX1/FConvX2;
}
for (int I = 0; I < FListView->Items->Count; I++){
if(FCurY == 0)
PrintHeader();
PrintLine(FListView->Items->Item[I]);
}
}__finally{
FPrinter->EndDoc();
}
}
void TPrintObj::PrintHeader()
{
TRect R;
if (FTitle != "" || FPageFormat != ""){
FPrinter->Canvas->Font->Size = FPrinter->Canvas->Font->Size + 2;
__try{
FHeight = FPrinter->Canvas->TextHeight(FTitle + FPageFormat + "1234567890");
R = Rect(FStarts[0], FCurY, FMaxX, FCurY + FHeight);
if(FTitle != "")
DrawText(FPrinter->Canvas->Handle, FTitle.c_str(), -1, &R, DT_LEFT | DT_TOP | DT_SINGLELINE);
if (FPageFormat != "")
DrawText(FPrinter->Canvas->Handle, Format(FPageFormat, ARRAYOFCONST((FPrinter->PageNumber))).c_str(),
-1, &R, DT_RIGHT | DT_TOP | DT_SINGLELINE);
NewLine();
}__finally{
FPrinter->Canvas->Font->Size = FPrinter->Canvas->Font->Size - 2;
}
NewLine();
}
FHeight = 0;
FPrinter->Canvas->Font->Style = TFontStyles()<< fsBold;
try{
for(int I = 0; I< FListView->Columns->Count; I++)
PrintRect(" " + FListView->Columns->Items[I]->Caption + " ", I);
NewLine();
}__finally{
FPrinter->Canvas->Font->Style = TFontStyles();
}
}
void TPrintObj::PrintLine(TListItem *AItem)
{
String AStr;
FHeight = 0;
for(int I= 0; I <= AItem->SubItems->Count; I++){
if(I == 0)
AStr = AItem->Caption;
else
AStr = AItem->SubItems->Strings[I - 1];
PrintRect(" " + AStr + " ", I);
}
NewLine();
}
void TPrintObj::PrintRect(const String S, int Column)
{
static int AlignFlags[] = {DT_LEFT, DT_RIGHT, DT_CENTER};
int CurHeight;
int TwoEms;
TRect R;
CurHeight = FPrinter->Canvas->TextHeight(S);
TwoEms = FPrinter->Canvas->TextWidth("M");
if(CurHeight > FHeight)
FHeight = CurHeight + 2;
R = TRect(FStarts[Column], FCurY,
FStarts[Column] + FWidths[Column], FCurY + CurHeight);
if(R.Left > FMaxX || R.Right - R.Left < TwoEms)
return; //Exit;
if(R.Right > FMaxX)
R.Right = FMaxX;
DrawText(FPrinter->Canvas->Handle, S.c_str(), -1, &R,
AlignFlags[FListView->Columns->Items[Column]->Alignment] | DT_TOP | DT_SINGLELINE);
}
|
Probado con Builder 5.
Saludos.
Ultima edición por escafandra el Mar 19 Ene, 2010 11:34 am, editado 2 veces |
|
| Volver arriba |
|
 |
bosoft Master

Registrado: 23 Oct 2005Mensajes: 342
|
Publicado: Lun 18 Ene, 2010 1:55 pm Asunto: |
|
|
Muchas gracias escafandra. Esta tarde lo pruebo.
Me he decidido por esta función ya que "en teoría" lo hace todo automáticamente
Gracias de nuevo
Saludos, Bosoft |
|
| Volver arriba |
|
 |
bosoft Master

Registrado: 23 Oct 2005Mensajes: 342
|
Publicado: Lun 18 Ene, 2010 5:50 pm Asunto: |
|
|
Hola escafandra:
después de unas cuantas horitas "pegándome" con la clase, no he podido hacerla funcionar.
Yo uso 2007 y no me entra el debug en la clase (que para eso quería la traducción)
Así pues he copiado la función print en mi cpp y lo he intentado desde allí
El primer error detectado es | Código: | FPrinter->BeginDoc();
// cambiado por
Printer()->BeginDoc();
|
Y al menos esta linea la trata bien, pero saltaba en la siguiente
| Código: | FPrinter->Canvas->Font = FListView->Font; |
lo que me dio a entender que no "pillaba" el puntero Fprinter correctamente. Lo cambié por Printer(), pero sigue saltando el mismo error. Pero si elimino esa linea, me salta en la siguiente
Me romperé un poco mas el coco haciendo una función en vez de una clase y cuando lo tenga correcto lo pasaré
Gracias
Saludos, Bosoft |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Lun 18 Ene, 2010 6:55 pm Asunto: |
|
|
Cambia | Código: | FPrinter->Canvas->Font = FListView->Font; |
por
| Código: | FPrinter->Canvas->Font->Assign(FListView->Font); |
El puntero FPrinter, asignado en el constructor no tiene porqué dar problemas.
No tengo la versión 2007 pero puedo probarlo en Builder 6
Saludos. |
|
| Volver arriba |
|
 |
bosoft Master

Registrado: 23 Oct 2005Mensajes: 342
|
Publicado: Lun 18 Ene, 2010 7:42 pm Asunto: |
|
|
¿Y te funciona?
Yo no he sido capaz de hacerlo funcionar, aunque compila sin errores
Probare a hacer las funciones en vez de clase para poder probar
Gracias de nuevo
Saludos, Bosoft |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Lun 18 Ene, 2010 8:40 pm Asunto: |
|
|
Si, me funciona. Lo he probado en Builder 5 con un pequeño programita que consta de un ListView y un botón de impresión:
| Código: | void __fastcall TForm1::Button1Click(TObject *Sender)
{
TPrintObj PO(Printer(), ListView1);
PO.Print();
} |
He probado sobre una impresora virtual PDFCreator 0.9.9 para no malgastar papel.
No he probado con otras versiones del Builder.
Saludos. |
|
| Volver arriba |
|
 |
bosoft Master

Registrado: 23 Oct 2005Mensajes: 342
|
Publicado: Lun 18 Ene, 2010 9:06 pm Asunto: |
|
|
Pues no hay manera, me sigue cascando en | Código: | FPrinter->Canvas->Font->Assign(FListView->Font); |
y si quito esa linea casca en
Debe ser de la versión 2007
Seguiré haciendo pruebas
Gracias por tu gran ayuda
Saludos, Bosoft |
|
| Volver arriba |
|
 |
bosoft Master

Registrado: 23 Oct 2005Mensajes: 342
|
Publicado: Lun 18 Ene, 2010 9:36 pm Asunto: |
|
|
Por fin, ya funciona
He quitado todas las referencias a FPrinter, las he cambiado por Printer() y ahora no casca
La llamada al creador ha quedado así | Código: | TPrintObj(TListView *AListView); |
Ahora me centraré en mejorar el código y añadirle mas ..... "cositas"
Por cierto ¿a ti te salen todos los items centrados? es como si no pillara bien el taLeftJustify de las columnas y las saca todas centradas
Muchísimas gracias por tu gran ayuda
Saludos, Bosoft |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mar 19 Ene, 2010 11:37 am Asunto: |
|
|
| bosoft escribió: | | Por fin, ya funciona | Perfecto.
| bosoft escribió: |
Por cierto ¿a ti te salen todos los items centrados? es como si no pillara bien el taLeftJustify de las columnas y las saca todas centradas |
Tienes razón. Cometí un error en el código. Donde dice:
| Código: | DrawText(FPrinter->Canvas->Handle, S.c_str(), -1, &R,
AlignFlags[FListView->Columns->Items[Column]->Alignment] || DT_TOP || DT_SINGLELINE); |
Debe decir: | Código: | DrawText(FPrinter->Canvas->Handle, S.c_str(), -1, &R,
AlignFlags[FListView->Columns->Items[Column]->Alignment] | DT_TOP | DT_SINGLELINE);
|
Está arreglado en el mensaje donde publico la clase.
Saludos. |
|
| Volver arriba |
|
 |
|
|
No puedes publicar temas nuevos en este foro No puedes responder a temas en este foro No puedes editar tus mensajes en este foro No puedes borrar tus mensajes en este foro No puedes votar en las encuestas de este foro
|
© 2002–2026 Club Builder · Funciona con phpBB.
|