Ver Mensaje Individual
  #11  
Antiguo 12-06-2016
Avatar de Dexter182
Dexter182 Dexter182 is offline
Miembro
 
Registrado: jul 2005
Ubicación: Argentina
Posts: 95
Reputación: 21
Dexter182 Va por buen camino
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;
//Calcula la cantidad de páginas que llevará la impresión
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);

    //Altura en pixeles de cada renglón
    AltRenglon   := Printer.Canvas.Font.Height + (Printer.Canvas.Font.Height * 0.3);

    //Cantidad de renglones por página
    CantRenglon := Round(Printer.PageHeight / AltRenglon) - 6;

    //Calcula la cantidad de páginas que necesitará el presupuesto
    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);
//Realiza las impresiones en papel de los presupuestos
var
  NumHoja      : byte;
  i            : Integer;
  Fila         : Integer;
  PosY         : Integer;
  CantPaginas  : Integer;
begin
  try

    If Printer.Printing then Printer.Abort;

    Printer.Title := 'Presupuesto';

    //Define que páginas se imprimirán
    If RadioButton_Todo.Checked = True then
      begin
        Fila        := 1;
        NumHoja     := 1;
        CantPaginas := Paginas;
      end
    Else //Si RadioButton_Paginas está seleccionado
      begin
        //Define desde que página comenzará la impresión
        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;
        //Define en que que página finalizará la impresión
        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); // Equivalente a Printer.Canvas.Font.Size := 10;
      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); // Equivalente a Printer.Canvas.Font.Size := 14;
          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; {while}

    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!
Responder Con Cita