bosoft Master

Registrado: 23 Oct 2005Mensajes: 342
|
Publicado: Mie 03 Feb, 2010 12:11 pm Asunto: Impresión de un ListView |
|
|
Después de darle muchas vueltas, por fin he terminado una función que imprime un ListView en cualquier impresora.
Antes de nada debo agradecer a escafandra su inestimable ayuda por echarme una mano en traducir un código de delphi sin el cual no hubiese tirado adelante el proyecto
Para llamar a selprint debemos usar esto | Código: | Tselprint *selprint =new Tselprint (this);
selprint->PListView=data; // (nombre del FListView a imprimir)
selprint->Title="Listado de datos"; // ="" si no queremos titulo
selprint->PageFormat="Página %d"; //="" si no queremos número de página
selprint->Ajust=true; // se autoajustan las columnas o false
selprint->FicheroIni=directorio+"Mi.ini"; // para guardar el último listado
selprint->ClaveIni="ListadoCli"; // clave del ini para este listado
try {
selprint->ShowModal();
} __finally {
selprint->Free();
}
|
Creo que está claro, si hay dudas preguntar
Hay que incluir el h en el cpp con use unit. Y Poner el form de selprint en available forms de las propiedades del proyecto
ahora sel_print_listview.h | Código: | //---------------------------------------------------------------------------
#ifndef print_listview_selH
#define print_listview_selH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Buttons.hpp>
#include <ComCtrls.hpp>
#include <Dialogs.hpp>
#include <ExtCtrls.hpp>
#include <inifiles.hpp>
//---------------------------------------------------------------------------
class Tselprint : public TForm
{
__published: // IDE-managed Components
TSpeedButton *SpeedButton1;
TSpeedButton *SpeedButton2;
TGroupBox *GroupBox1;
TComboBox *printers;
TEdit *copias;
TRadioGroup *orienta;
TUpDown *UpDown1;
TStaticText *StaticText1;
TGroupBox *selec;
TGroupBox *sumar;
void __fastcall FormPaint(TObject *Sender);
void __fastcall SpeedButton1Click(TObject *Sender);
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
void __fastcall SpeedButton2Click(TObject *Sender);
void __fastcall printersChange(TObject *Sender);
void __fastcall selecClick(TObject *Sender);
protected:
int FCurY;
int FMaxX;
int FMaxY;
int FHeight;
int *ColStart;
int *ColWidth;
int *ItemLen;
double *SumaCol;
TCheckBox* col[50];
TCheckBox* sum[50];
void NewLine();
void PrintHeader();
void PrintLine(TListItem *AItem);
void PrintRect(const String S, int Column);
double ADouble(String Valor);
private: // User declarations
public: // User declarations
__fastcall Tselprint(TComponent* Owner);
TListView *PListView;
String Title;
String PageFormat;
bool Ajust;
String FicheroIni;
String ClaveIni;
};
//---------------------------------------------------------------------------
extern PACKAGE Tselprint *selprint;
//---------------------------------------------------------------------------
#endif |
y sel_print_listview.cpp | Código: | //---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "print_listview_sel.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
Tselprint *selprint;
bool selpaint=false;
//---------------------------------------------------------------------------
__fastcall Tselprint::Tselprint(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall Tselprint::FormPaint(TObject *Sender)
{
int i,c=0,count;
String Valor;
if(PListView==NULL) return;
if(selpaint) return;
selpaint=true;
count=PListView->Columns->Count;
// ajustar ventana
count-=16; // las 4 primeras correcto
if(count>0){
if((count/4)*4!=count) c=4;
count=(count+c)/4; //lineas que faltan
count*=20;
ClientHeight+=count*2;
Top-=count;
selec->Height+=count;
sumar->Height+=count;
sumar->Top+=count;
}
// poner las columnas
for(i=0,c=0;i<PListView->Columns->Count;i++,c++){
if(c>3) c=0;
col[i] = new TCheckBox(this);
col[i]->Parent=selec;
col[i]->Visible=true;
col[i]->Top =i/4*20+15;
col[i]->Width=118;
col[i]->Left=20+c*120;
col[i]->Checked=PListView->Columns->Items[i]->Width;
col[i]->Caption=PListView->Columns->Items[i]->Caption;
col[i]->Name = "col"+IntToStr(i);
col[i]->OnClick=selecClick;
}
// poner las columnas a sumar
for(int i=0,c=0;i<PListView->Columns->Count;i++,c++){
if(c>3) c=0;
sum[i] = new TCheckBox(this);
sum[i]->Parent=sumar;
sum[i]->Visible=true;
sum[i]->Top =i/4*20+15;
sum[i]->Width=118;
sum[i]->Left=20+c*120;
sum[i]->Checked=false;
sum[i]->Enabled=PListView->Columns->Items[i]->Alignment==taRightJustify;
sum[i]->Caption=PListView->Columns->Items[i]->Caption;
sum[i]->Name = "sum"+IntToStr(i);
}
// imprsoras
printers->Items->AddStrings(Printer()->Printers);
printers->ItemIndex=Printer()->PrinterIndex;
// abrir ini si existe
if(FicheroIni!=""){
TIniFile *ini = new TIniFile (FicheroIni);
Valor=ini->ReadString(ClaveIni,"printer",Printer()->Printers->Strings[Printer()->PrinterIndex]);
orienta->ItemIndex=ini->ReadInteger(ClaveIni,"orientacion",0);
for(i=0;i<PListView->Columns->Count;i++){
sum[i]->Checked=ini->ReadBool(ClaveIni,"suma"+IntToStr(i),false);
col[i]->Checked=ini->ReadBool(ClaveIni,"Col"+IntToStr(i),true);
}
delete (ini);
printers->ItemIndex=printers->Items->IndexOf(Valor);
}
}
//---------------------------------------------------------------------------
// funcion para calculos de impresión
void __fastcall Tselprint::SpeedButton1Click(TObject *Sender)
{
int I, FConvX1, FConvX2,resto,ultimo,actual;
double porpunto;
Printer()->Title=Title;
Printer()->Copies=StrToInt(copias->Text);
Printer()->Orientation=orienta->ItemIndex;
FHeight=0;
Printer()->BeginDoc();
__try{
Printer()->Canvas->Font = PListView->Font;
FCurY = 0;
FMaxX = Printer()->PageWidth;
FMaxY = Printer()->PageHeight;
FConvX1 = Printer()->Canvas->TextWidth("M");
FConvX2 = PListView->Canvas->TextWidth("M");
if(ColStart) delete [] ColStart;
ColStart = new int[PListView->Columns->Count];
if(ColWidth) delete [] ColWidth;
ColWidth = new int[PListView->Columns->Count];
if(ItemLen) delete [] ItemLen;
ItemLen = new int[PListView->Columns->Count];
if(SumaCol) delete [] SumaCol;
SumaCol = new double[PListView->Columns->Count];
for (int I = 0; I < PListView->Columns->Count; I++){
if(I == 0) ColStart[I] = FConvX1;
else ColStart[I] = ColStart[I-1]+ColWidth[I-1]+FConvX1;
ColWidth[I] = PListView->Columns->Items[I]->Width * FConvX1/FConvX2;
}
// ajustar ancho al maximo (sobrante)
// sumar ancho de linea
for( int c=0;c < PListView->Columns->Count; c++){
int cuan;
SumaCol[c]=0;
ItemLen[c]=0;
if(col[c]->Checked==false){
ItemLen[c]=0;
ColWidth[c]=0;
ColStart[c]= c==0 ? FConvX1 : 0;
continue;
}
Printer()->Canvas->Font->Style = TFontStyles()<< fsBold;
if(sum[c]->Checked){
ItemLen[c]=Printer()->Canvas->TextWidth("99.999.999,99");
ColWidth[c]=ItemLen[c];
}
cuan=Printer()->Canvas->TextWidth(PListView->Columns->Items[c]->Caption+"M ");
if(ItemLen[c]<cuan) ItemLen[c]=cuan;
Printer()->Canvas->Font->Style = TFontStyles();
// calculo del maximo de cada item
for(int I=0;I<PListView->Items->Count;I++){
String Valor;
if(!c) Valor=PListView->Items->Item[I]->Caption;
else Valor=PListView->Items->Item[I]->SubItems->Strings[c-1];
cuan=Printer()->Canvas->TextWidth(Valor.Trim()+"M ");
if(ItemLen[c]<cuan) ItemLen[c]=cuan;
if(sum[c]->Checked) SumaCol[c]+=ADouble(Valor);
}
}
// hacer 2 veces el reparto de la sobra
for(int i=0; i<4; i++){
ultimo=0;
actual=0;
for (int I = 0; I < PListView->Columns->Count; I++){
if(ItemLen[I]<ColWidth[I]) ColWidth[I]=ItemLen[I];
else ultimo+=ColWidth[I];
actual+=ColWidth[I];
}
resto=FMaxX-actual-FConvX1; // descontar una letra "M"
porpunto=(double)resto/ultimo;
for (int I = 0; I < PListView->Columns->Count; I++){
if(Ajust && ItemLen[I]>ColWidth[I] && porpunto){
ColWidth[I]+=ColWidth[I]*porpunto;
if(ItemLen[I]<ColWidth[I]) ColWidth[I]=ItemLen[I];
}
// reajustar el inicio de cada columna
if(I!=0) ColStart[I] = ColStart[I - 1] + ColWidth[I - 1];
// si no cabe en la pag, se quita
if(ColStart[I]+ColWidth[I]>FMaxX){
ItemLen[I]=0;
ColWidth[I]=0;
ColStart[I]= I==0 ? FConvX1 : 0;
}
}
}
// impresion
for (int I = 0; I < PListView->Items->Count; I++){
if(FCurY == 0) PrintHeader();
PrintLine(PListView->Items->Item[I]);
}
// revisar si hay sumacols
for (I = 0; I < PListView->Columns->Count; I++)
if(sum[I]->Checked) break;
if(I<PListView->Columns->Count){
I=FCurY+4;
FCurY+=6;
Printer()->Canvas->Font->Style = TFontStyles()<< fsBold;
for (int i = 0; i < PListView->Columns->Count; i++)
if(sum[i]->Checked)
PrintRect(FloatToStrF(SumaCol[i],ffNumber,10,2), i);
Printer()->Canvas->Font->Style = TFontStyles();
}
// poner las lineas
for (int i = 0; i < PListView->Columns->Count; i++)
if(sum[i]->Checked){
int w=Printer()->Canvas->TextWidth(" ");
Printer()->Canvas->Pen->Width=2;
Printer()->Canvas->MoveTo(ColStart[i]+w, I);
Printer()->Canvas->LineTo(ColStart[i]+ColWidth[i]-FConvX1,I);
}
}__finally{
Printer()->EndDoc();
}
Close();
}
//---------------------------------------------------------------------------
void __fastcall Tselprint::FormClose(TObject *Sender, TCloseAction &Action)
{
int i;
if(FicheroIni!=""){
TIniFile *ini = new TIniFile (FicheroIni);
ini->WriteString(ClaveIni,"printer",printers->Text);
ini->WriteInteger(ClaveIni,"orientacion",orienta->ItemIndex);
for(i=0;i<PListView->Columns->Count;i++){
ini->WriteBool(ClaveIni,"suma"+IntToStr(i),sum[i]->Checked);
ini->WriteBool(ClaveIni,"Col"+IntToStr(i),col[i]->Checked);
}
delete (ini);
}
for(i=0;i<PListView->Columns->Count;i++){
delete col[i];
delete sum[i];
}
selpaint=false;
Action=caFree;
}
//---------------------------------------------------------------------------
void __fastcall Tselprint::SpeedButton2Click(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
void Tselprint::NewLine()
{
FCurY += FHeight;
if (FCurY > FMaxY - 2 * FHeight){
FCurY = 0;
Printer()->NewPage();
}
}
//---------------------------------------------------------------------------
void Tselprint::PrintHeader()
{
TRect R;
if (Title != "" || PageFormat != ""){
Printer()->Canvas->Font->Size = Printer()->Canvas->Font->Size + 2;
__try{
FHeight = Printer()->Canvas->TextHeight(Title + PageFormat + "1234567890");
R = Rect(ColStart[0], FCurY, FMaxX-Printer()->Canvas->TextWidth("M"), FCurY + FHeight);
if(Title != "")
DrawText(Printer()->Canvas->Handle, Title.c_str(), -1, &R, DT_LEFT | DT_TOP | DT_SINGLELINE);
if (PageFormat != "")
DrawText(Printer()->Canvas->Handle, Format(PageFormat, ARRAYOFCONST((Printer()->PageNumber))).c_str(),
-1, &R, DT_RIGHT | DT_TOP | DT_SINGLELINE);
NewLine();
}__finally{
Printer()->Canvas->Font->Size = Printer()->Canvas->Font->Size - 2;
}
NewLine();
}
FHeight = 0;
Printer()->Canvas->Font->Style = TFontStyles()<< fsBold;
try{
for(int I = 0; I< PListView->Columns->Count; I++)
PrintRect(PListView->Columns->Items[I]->Caption,I);
NewLine();
}__finally{
Printer()->Canvas->Font->Style = TFontStyles();
}
}
//---------------------------------------------------------------------------
void Tselprint::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 Tselprint::PrintRect(const String S, int Column)
{
static int AlignFlags[] = {DT_LEFT,DT_RIGHT ,DT_CENTER };
int CurHeight;
int TwoEms;
TRect R;
CurHeight = Printer()->Canvas->TextHeight(S);
TwoEms = Printer()->Canvas->TextWidth("M");
if(CurHeight > FHeight)
FHeight = CurHeight + 2;
R = TRect(ColStart[Column], FCurY,
ColStart[Column] + ColWidth[Column]-TwoEms, FCurY + CurHeight);
if(R.Left > FMaxX || R.Right - R.Left < TwoEms) return; //Exit;
if(R.Right > FMaxX) R.Right = FMaxX;
DrawText(Printer()->Canvas->Handle, S.c_str(), -1, &R,
AlignFlags[PListView->Columns->Items[Column]->Alignment] | DT_TOP | DT_SINGLELINE);
}
//---------------------------------------------------------------------------
double Tselprint::ADouble(String Valor)
{
String Valor2;
double numero;
Valor2=StringReplace(Valor,".","",TReplaceFlags() << rfReplaceAll);
Valor=StringReplace(Valor2,",",".",TReplaceFlags() << rfReplaceAll);
numero=atof(Valor.c_str());
return (numero);
}
void __fastcall Tselprint::printersChange(TObject *Sender)
{
Printer()->PrinterIndex=printers->ItemIndex;
}
//---------------------------------------------------------------------------
// si se desactiva una columna, la suma tambien
void __fastcall Tselprint::selecClick(TObject *Sender)
{
if(!selpaint) return;
for(int i=0; i<PListView->Columns->Count ; i++){
if(col[i]->Checked==false){
sum[i]->Checked=false;
sum[i]->Enabled=false;
}
else
sum[i]->Enabled=PListView->Columns->Items[i]->Alignment==taRightJustify;
}
}
//---------------------------------------------------------------------------
|
Si alguien quiere el proyecto completo con el dfm y los archivos cpp y h que lo diga. Por si el foro "se come" cosas.
El sistema imprime todos los items del listview referenciado, y permite seleccionar las columnas a imprimir así como hacer la suma al final si están justificados a la derecha
Esto quería pasarlo a un componente para poder usarlo con mayor facilidad, pero no he podido, o mejor dicho, no he sabido
También creo que se puede mejorar. Estoy abierto a ello
Saludos, Bosoft |
|