Después de mucho, mucho tiempo, y porque quería hacerle varios cambios, volví a ponerme las pilas con solucionar de una manera más elegante varios de los problemas que tenía mi código de impresión.
Luego de leer bastante a través de este foro y varias páginas en Internet, pero por sobre todo luego de muchísimas pruebas, logré que funcione como yo quería.
Finalmente decidí dejar de usar el PrintDialog y creé mi propio formulario de impresión, que consiste en un simple ComboBox para elegir la impresora y un pequeño GroupBox dónde están embebidos los componentes que me permiten decidir las opciones del intervalo de impresión.
Por si le sirve a alguien, les dejo el código...
Primero les paso el código de la parte que más dolores de cabeza me llevó hacer que funcione bien y tenga consistencia entre diferentes impresoras: el cálculo de cantidad de páginas. Este procedimiento lo llamo ni bien se abre el formulario de impresión y cada vez que el usuario cambia de impresora en el ComboBox:
Código Delphi
[-]procedure TForm_Impresion.CalcularPaginas;
var
CantFilas : Integer;
begin
try
If Origen_Impresion = Venta1 then
CantFilas := Form_Venta.StringGrid_Venta_V1.RowCount
Else
CantFilas := Form_Venta.StringGrid_Venta_V2.RowCount;
Printer.Canvas.Font.Name := 'Arial';
Printer.Canvas.Font.Height := MulDiv(GetDeviceCaps(Printer.Handle, LOGPIXELSY), 10, 72);
AltRenglon := Printer.Canvas.Font.Height + (Printer.Canvas.Font.Height * 0.3);
CantRenglon := Round(Printer.PageHeight / AltRenglon) - 6;
If CantRenglon > (CantFilas - 1) then
Paginas := 1
Else
If CantRenglon > 0 then
Paginas := Ceil((CantFilas - 1) / CantRenglon)
Else
Paginas := 0;
SpinEdit_Desde.MaxValue := Paginas;
SpinEdit_Hasta.MaxValue := Paginas;
SpinEdit_Desde.Value := 1;
SpinEdit_Hasta.Value := Paginas;
except
on EPrinter do
MessageBox(Handle, 'Error al calcular la cantidad de páginas.'+#13#10+
'No se encuentra impresora.', 'Error!', MB_OK+MB_ICONERROR);
end;
end;
Y finalmente el procedimiento Impresion, que es muy similar al código anterior, pero con unos pequeños cambios:
Código Delphi
[-]procedure TForm_Impresion.Imprimir(StringGrid: TStringGrid; Edit: TEdit);
var
NumHoja : byte;
i : Integer;
Fila : Integer;
PosY : Integer;
CantPaginas : Integer;
begin
try
If Printer.Printing then Printer.Abort;
Printer.Title := 'Presupuesto';
If RadioButton_Todo.Checked = True then
begin
Fila := 1;
NumHoja := 1;
CantPaginas := Paginas;
end
Else begin
If SpinEdit_Desde.Value = 1 then
begin
Fila := 1;
NumHoja := 1;
end
Else
begin
Fila := Floor((SpinEdit_Desde.Value - 1) * CantRenglon) + 1;
NumHoja := Floor(SpinEdit_Desde.Value);
end;
CantPaginas := Floor(SpinEdit_Hasta.Value - SpinEdit_Desde.Value + 1);
end;
Printer.BeginDoc;
While Fila < StringGrid.RowCount do begin
Printer.Canvas.Font.Name := 'Arial';
Printer.Canvas.Font.Height := MulDiv(GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSY), 10, 72); Printer.Canvas.Font.Style := [fsBold, fsUnderline];
Printer.Canvas.TextOut(80, Round(AltRenglon * 1.5), 'Descripción');
Printer.Canvas.TextOut(Round(Printer.PageWidth * 0.68) - Printer.Canvas.TextWidth('Cant.'), Round(AltRenglon * 1.5), 'Cantidad');
Printer.Canvas.TextOut(Round(Printer.PageWidth * 0.83) - Printer.Canvas.TextWidth('Precio'), Round(AltRenglon * 1.5), 'Precio');
Printer.Canvas.TextOut(Printer.PageWidth - 80 - Printer.Canvas.TextWidth('Subtotal'), Round(AltRenglon * 1.5), 'Subtotal');
Printer.Canvas.MoveTo(0, Round(AltRenglon * 2));
Printer.Canvas.Font.Style := [];
For i := 1 to CantRenglon do
If Fila <= StringGrid.RowCount then
begin
PosY := Printer.Canvas.PenPos.Y + Round(AltRenglon);
Printer.Canvas.TextOut(80, PosY, StringGrid.Cells[1,Fila]);
Printer.Canvas.TextOut(Round(Printer.PageWidth * 0.68) - Printer.Canvas.TextWidth(StringGrid.Cells[2,Fila]), PosY, StringGrid.Cells[2,Fila]);
Printer.Canvas.TextOut(Round(Printer.PageWidth * 0.83) - Printer.Canvas.TextWidth(StringGrid.Cells[3,Fila]), PosY, StringGrid.Cells[3,Fila]);
Printer.Canvas.TextOut(Printer.PageWidth - 84 - Printer.Canvas.TextWidth(StringGrid.Cells[4,Fila]), PosY, StringGrid.Cells[4,Fila]);
Fila := Fila + 1;
end;
Printer.Canvas.Font.Style := [fsBold];
If NumHoja <> Paginas then
Printer.Canvas.TextOut(80, Printer.PageHeight - Round(AltRenglon * 2 ), 'Hoja Nº ' + IntToStr(NumHoja))
Else
begin
PosY := Printer.Canvas.PenPos.Y + Round(AltRenglon);
Printer.Canvas.TextOut(80, PosY, 'Hoja Nº ' + IntToStr(NumHoja));
Printer.Canvas.Font.Height := MulDiv(GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSY), 14, 72); Printer.Canvas.TextOut(Printer.PageWidth - 80 - Printer.Canvas.TextWidth('TOTAL: ' + Edit.Text), PosY -10, 'TOTAL: '+Edit.Text);
end;
If Printer.PageNumber < CantPaginas then
begin
Printer.NewPage;
NumHoja := NumHoja + 1;
end
end;
Printer.EndDoc;
except
on EPrinter do
MessageBox(Handle, 'Imposible imprimir.'+#13#10+'No se encuentra impresora.', 'Error!', MB_OK+MB_ICONERROR);
end;
end;
"AltRenglon", "CantRenglon" y "Paginas" son variables privadas del formulario del tipo Integer.
Ahora solo me resta solucionar un "AccessViolation" que sucede solamente con una impresora HP compartida por red al mandar la orden de impresión y la PC se encuentra apagada.
Espero no demorar tres años en solucionarlo.
Saludos!