Difference between revisions of "Using the printer/es"

From Free Pascal wiki
(Introducción)
m (Fixed syntax highlighting; deleted category included in page template)
 
(28 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 +
{{Using the printer}}
 +
[[category:Español]][[category:Castellano]]
 +
 
==Introducción==
 
==Introducción==
 
La impresión es fácil en FreePascal, pero solamente después de seguir algunos pasos requeridos, una vez que se comprenden estos primeros pasos ya se estaría en condiciones de pasar a conceptos más avanzados de impresión.
 
La impresión es fácil en FreePascal, pero solamente después de seguir algunos pasos requeridos, una vez que se comprenden estos primeros pasos ya se estaría en condiciones de pasar a conceptos más avanzados de impresión.
Este artículo trata dichos pasos, que han sido recogidos de varios foros y ejemplos. Después de explicar los pasos básicos se realizará la impresión de unos texto para a continuación plantear sugerencias sobre impresión avanzada.
+
Este artículo trata dichos pasos, que han sido recogidos de varios foros y ejemplos. Después de explicar los pasos básicos se realizará la impresión de unos textos para a continuación plantear sugerencias sobre impresión avanzada.
  
 
==Los pasos básicos==
 
==Los pasos básicos==
  
Lo siguiente que se debe hacer para ser capaz de utilizar las impresoras es:
+
Se necesita seguir los siguientes pasos para poder utilizar las impresoras:
  
 
# Añadir el paquete '''Printer4Lazarus''' a los requerimientos del programa.
 
# Añadir el paquete '''Printer4Lazarus''' a los requerimientos del programa.
 
# Añadir la unit '''Printers''' a la sección '''uses''' en la unidad.
 
# Añadir la unit '''Printers''' a la sección '''uses''' en la unidad.
# Utilizar el objeto existenge '''Printer'''.
+
# Utilizar el objeto existente '''Printer'''.
  
 
===Añadiendo el paquete Printer4Lazarus a los requerimientos del proyecto===
 
===Añadiendo el paquete Printer4Lazarus a los requerimientos del proyecto===
Line 17: Line 20:
 
En el IDE de Lazarus, realizar lo siguiente:
 
En el IDE de Lazarus, realizar lo siguiente:
  
# In the '''Project''' menu, click '''Project Inspector'''. A window is shown with a tree view, one of the branches is named ''Required Packages''. By default, the ''Required Packages'' branch shows the ''LCL'' package.
+
# En el menú, dentro de '''Proyecto''', haz click en '''Inspector de Proyecto'''. A continuación se muestra una ventana con una vista en árbol, una de sus ramas se llama  ''Paquetes Requeridos''. Por defecto la rama de ''Paquetes Requeridos'' muestra el paquete ''LCL''.
# Click the '''Add''' button, the button with the plus sign at the top of the window.
+
# Hacer click en el pulsador '''Añadir''', es el que tiene dibujado el signo +.
# Open the '''New Requirements''' page.
+
# Abre la solapa '''Nuevo requerimiento'''.
# From the '''Package Name''' list box, select ''Printer4Lazarus''.
+
# En el cuadro de listado '''Nombre de Paquete''' selecciona ''Printer4Lazarus''.
# Click '''OK'''.
+
# Haz click en '''Crear Nuevo Requisito'''.
# ''Printer4Lazarus'' is now shown in the ''Required Packages'' branch.
+
# Con esto ya se muestra ''Printer4Lazarus'' en la rama de ''Paquetes Requeridos''.
  
===Añadiendo la unidad '''Printers''' a la sección '''uses''' de tu unidad===
+
===Añadiendo la unidad '''Printers''' a la sección '''uses''' section de tu unidad===
Esto es simple y straight forward tal como se muestra a continuación:
 
  
<syntaxhighlight>unit MainUnt;
+
Esto es simple y fácil de hacer, pareciéndose el resultado a esto:
 +
 +
<syntaxhighlight lang=pascal>unit MainUnt;
 
   
 
   
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 36: Line 40:
 
   Classes, SysUtils, Forms, Printers;</syntaxhighlight>
 
   Classes, SysUtils, Forms, Printers;</syntaxhighlight>
  
===Utilizando el objeto '''Printer''' existente===
+
===Utilizando el objeto Printer===
Assuming you want to click a button to print a text. On you form you put a button called '''PrintBtn''' and in the '''OnClick''' event you can now use the following:
+
Asumiremos que se necesita un pulsador para imprimir un texto. Dicho pulsador se llama '''PrintBtn''' y precisa del evento '''OnClick''', una vez hecho esto ya lo podemos utilizar.
  
<syntaxhighlight>procedure TForm1.PrintBtnClick(Sender: TObject);
+
<syntaxhighlight lang=pascal>procedure TForm1.PrintBtnClick(Sender: TObject);
 
const
 
const
   LEFTMARGIN = 100;
+
   LEFTMARGIN = 100; {margen izquierdo, lo definimos como una constante}
   HEADLINE = 'I Printed My Very First Text On ';
+
   HEADLINE = 'Mi primera impresión de texto utilizando Lazarus '; {Línea de cabecera a imprimir}
 
var
 
var
   YPos, LineHeight, VerticalMargin: Integer;
+
   YPos, LineHeight, VerticalMargin: Integer; {Posición Y, Alto de línea, Margen vertical }
 
   SuccessString: String;
 
   SuccessString: String;
 
begin
 
begin
 
   with Printer do
 
   with Printer do
   try
+
   try { realiza la prueba por si se puede imprimir, caso de que no se realiza una acción, caso de que si realiza finally }
     BeginDoc;
+
     BeginDoc;   { Comenzamos el documento a imprimir }
     Canvas.Font.Name := 'Courier New';
+
     Canvas.Font.Name := 'Courier New'; { Ya tenemos el Canvas pues a llenarlo, en este caso definimos el nombre de la fuente }
     Canvas.Font.Size := 10;
+
    { para el texto que vamos a imprimir }
     Canvas.Font.Color := clBlack;
+
     Canvas.Font.Size := 10; { Definimos el tamaño para el tipo de fuente (nombre de la fuente) de texto que hemos escogido }
     LineHeight := Round(1.2 * Abs(Canvas.TextHeight('I')));
+
     Canvas.Font.Color := clBlack; { Definimos el color que va a tener nuestra fuente de texto gráfica }
     VerticalMargin := 4 * LineHeight;
+
     LineHeight := Round(1.2 * Abs(Canvas.TextHeight('I'))); { Definimos la altura de cada línea }
     // There we go
+
     VerticalMargin := 4 * LineHeight; { Definimos el margen vertical }
     YPos := VerticalMargin;
+
     { una vez hecho lo anterior ya podemos ubicar nuestro texto en el lienzo }
     SuccessString := HEADLINE + DateTimeToStr(Now);  
+
     YPos := VerticalMargin; { Definimos la posición Y en el lienzo }
     Canvas.TextOut(LEFTMARGIN, YPos, SuccessString);
+
     SuccessString := HEADLINE + DateTimeToStr(Now); { Concatenamos nuestro texto de cabecera con la fecha actual }
 +
     Canvas.TextOut(LEFTMARGIN, YPos, SuccessString); { Escribimos nuestro texto donde lo queremos poner }
 
   finally
 
   finally
     EndDoc;
+
     EndDoc; { Como ya tenemos el lienzo dibujado con nuestro texto, con EndDoc lo enviamos a imprimir }
 
   end;
 
   end;
 
end;</syntaxhighlight>
 
end;</syntaxhighlight>
  
Did I write ''basic'' and ''simple''. The above example is somewhat complex. Next to the basic text output in the bold line, it also provides an example of formatting your text.
+
Con esto hemos escrito algo ''basico'' y ''simple''. El siguiente ejemplo es algo más complejo. Next to the basic text output in the bold line, it also provides an example of formatting your text.
 +
 
 +
Desde '''begin''' a '''end;''' sucede lo siguiente:
 +
 
 +
* Se puede utilizar el objeto ''Printer'' directamente como en el ejemplo anterior, sin utilizar tu propia variable, o como utilizaremos en el siguiente ejemplo con con ''MiImpresora''. Por lo tanto el objeto MiImpresora no es realmente necesario, se ha utilizado para dar claridad al código fuente utilizado.
 +
 
 +
* Se comienza la preparación de impresión con ''MiImpresora.BeginDoc'' pero todavía no se envía nada a la impresora, por lo que podemos ir rellenando en unas coordenadas de ubicación sobre el lienzo (Canvas) el texto deseado con una tipografía, un color,....hasta que se finalice el bloque con ''MiImpresora.EndDoc;''.
 +
 
 +
* Printer utiliza un lienzo (Canvas) para dibujar sobre el mismo el contenido tal como lo haríamos en una hoja de papel (bien sea texto (con su tipografía, formato, color....), líneas, dibujos, etc). Para ir rellenando el lienzo anteponemos Canvas seguido de un punto (Canvas.) luego que que deseamos poner, en este caso al ser texto lo primero que hacemos es establecer la tipografía con ''Canvas.Font'', por lo tanto ya hemos puesto un objeto tipo font. Ponemos otro punto (Canvas.Font.) y por tanto dentro de font podemos definir la tipografía por su nombre (Canvas.Font.Name) que en este caso lo establece a Courier New, pero podríamos establecer su tamaño (Canvas.Font.Size) o su color (Canvas.Font.Color) o cualquiera otra propiedad que ese objeto nos permita establecer.
 +
Una vez definido esto con TextOut escribimos nuestro texto en el lienzo.
 +
 
 +
* Todo lo que se dibuja en un lienzo (canvas) debe posicionarse utilizando coordenadas (podeis imaginarlo como un papel milimetrado donde en unas coordenadas de partida ubicais un objeto (texto en nuestro caso pero podría haber sido una foto, un dibujo con líneas...). Como en este caso se trata de texto nos interesa definir la altura de la línea ''LineHeight''. Se puede hacer lo mismo para la posición horizontal, en este caso estableciendo el valor del margen izquierdo ''LEFTMARGIN''.
 +
* Una vez establecido todo lo anterior ya podemos escribir el texto en el lienzo mediante la llamada a''TextOut''.
 +
* Con el lienzo dibujado a nuestro gusto solamente nos resta enviarlo a la impresora y para ello utilizamos MiImpresora.EndDoc.
 +
 
 +
En algunos foros se sugiere que para un correcto funcionamiento se utilice el diálogo ''PrintDialog'' pero no he encontrado que esto sea necesario (obligatorio) en ningún caso.
 +
 
 +
==Siguientes pasos==
 +
 
 +
Después de realizar los pasos anteriores ya podemos avanzar más en los siguientes, dejando al lector otras pruebas como:
 +
 
 +
* Realizar el dibujo en papel.
 +
* Formatear el texto de forma agradable.
 +
* Seleccionar otra impresora y comparar los resultados.
 +
 
 +
En la distribución Lazarus se incluye un proyecto de ejemplo que utiliza un Raw para imprimir a la impresora. Se puede encontrar este ejemplo en la siguiente ubicación (en windows) C:\lazarus\components\printers\samples\rawmode\rawmodetest.lpi.
 +
En otro ejemplo se muestra como seleccionar otra impresora, lo podéis encontrar en C:\lazarus\components\printers\samples\dialogs\selectprinter.lpi.
 +
 
 +
==Pasos avanzados==
 +
 
 +
El objeto '''printer''' permite primariamente dibujar en un lienzo (canvas) y enviar esta imagen a la impresora. Si continuamos en la senda ya mostrada, entonces se puede utilizar el método canvas para dibujar texto, elipses, rectángulos o cualquier otra cosa que se nos ocurra. Esto se muestra ya sumamente interesante para cualquier programador serio.
 +
Por ejemplo si estás trabajando en un programa de CAD más perfeccionado o en algún organizador de imágenes y quieres imprimir el estupendo resultado en el lienzo (canvas), entonces tratar de plasmar ese resultado mediante llamadas al lienzo no es el camino ya que directamente se tiene el cuadro.
 +
 
 +
Todos y cada uno de los controles que se emplazan en el formulario también dibujan una imagen en un objeto TCanvas tal como el de la impresora (printer). Imagínate que estás tratando de implementar un programa de visualización preliminar. Primeramente creas un formulario y dentro de él pones un TPanel, el cual aporta el agradable fondo grisaceo de la vista previa. En este panel pones otro objeto TPanel llamado ''page''. Esta ''page'' será de color blanco y representará el papel. En esta página se puede poner un objeto TSahpe, por ejemplo un vistoso rectánculo redondeado rojo.
 +
A continuación prueba lo siguiente en el evento '''PrintBtnClick''' del método:
 +
 
 +
<syntaxhighlight lang=pascal>MiImpresora.BeginDoc;
 +
  page.PaintTo(MiImpresora.Canvas, 0, 0);
 +
MiImpresora.EndDoc;</syntaxhighlight>
 +
 
 +
Esto es lo que sucede:
 +
* ''BeginDoc'' comienza la impresión del documento, o composición (pero no se envía todavía nada a la impresora).
 +
* ''page.PaintTo'' envía la salida de nuestro objeto TPanel al lienzo (que representa la página) de la impresora. Fíjate en lo siguiente:
 +
*# Puedes utilizar el método PaintTo de cualquier control en la jerarquía de controles. Puedes además enviar la salida de la ventana completa a printer si lo necesitas.
 +
*# Puedes enviar la salida de cualquier control a printer con el método PaintTo. Para enviar la salida de tu organizador de imágenes a la impresora puedes enviar la salida de TImage a la impresora.
 +
*# TCanvas también tiene un método para copiar rectángulo desde otro canvas. Sin embargo, solo se puede hacer si un objeto dibuja realmente a un lienzo (canvas). Creo que la mayor parte de los controles recaen en contenedores para proveer de un canvaas real, por lo tanto no puedes copiar rectángulos desde cualquier control. Al menos esto no me han funcionado a mí.
 +
*# Asegúrate de que el control que necesitas dibujar a la impresora está visible. Si el control no es visible entonces no se pintará nada ni siquiera a la impresora.
 +
 
 +
* ''EndDoc'' envía lo dibujado a la impresora seleccionada.....
 +
 
 +
==Avanzando más contenido==
 +
 
 +
La impresora utiliza muchos más pixeles por pulgada (ppi: pixeles per inch) en su impresión en papel que los utilizados por un monitor para representar la misma información en pantalla. Como resultado, la salida que es redirigida desde la pantalla a la impresora aparece más pequeña cuando es impresa en papel. Es por tanto importante el escalando y control de la disposición para una buena salida impresa. Sería agradable si se pudiese obtener una salda impresa de tamaño exactamente igual a lo mostrado en pantalla.
 +
 
 +
Por el momento no nos estamos esforzando por el idea, solamente por la idea. Como se dijo anteriormente, los controles no tienen su propio lienzo (canvas) pero recaen en el lienzo (canvas) de un contenedor o dueño. Sin embargo, existen componentes que tienen su propio lienzo (canvas). Yo escogí TBitMap y funcionó como sigue:
 +
 
 +
<syntaxhighlight lang=pascal>procedure TForm1.PrintBtnClick(Sender: TObject);
 +
var
 +
  MiImpresora : TPrinter;
 +
  MiMapadeBits : TBitMap;
 +
begin
 +
  MiMapadeBits := TBitMap.Create;    { Creamos el objeto MiMapadeBits }
 +
  MiMapadeBits.Width := page.Width;  { Definimos su anchura }
 +
  MiMapadeBits.Height := page.Height; { Definimos su altura }
 +
  page.BorderStyle:=bsNone; { Definimos el estilo del borde a ninguno }
 +
  page.PaintTo(myBitMap.Canvas, 0, 0);
 +
  page.BorderStyle:=bsSingle;
 +
  //
 +
  MiImpresora := Printer;
 +
  MiImpresora.BeginDoc;
 +
    //page.PaintTo(MiImpresora.Canvas, 0, 0);
 +
    //MiImpresora.Canvas.Draw(0,0, myBitMap);
 +
    MiImpresora.Canvas.CopyRect(Classes.Rect(0, 0, MiImpresora.PaperSize.Width, MiImpresora.PaperSize.Height),
 +
      myBitMap.Canvas, Classes.Rect(0, 0, myBitMap.Width, myBitMap.Height));
 +
  MiImpresora.EndDoc; { Damos por finalizada la composición y enviamos el contenido del lienzo a la impresora }
 +
  MiMapadeBits.Free;  { Liberamos el recurso MiMapadeBits de la memoria }
 +
end;</syntaxhighlight>
  
From ''begin'' to ''end;'' the following happens.
+
Para este trabajo no utiliceis la unit ''Windows''. La unit ''Windows'' tiene otras definiciones para '''Rect'''. La descripción dedel código paso a paso del ejemplo anterior es la siguiente:
* You can use the ''Printer'' object directly, without your own variable such as ''MyPrinter''. So, the MyPrinter object is not really needed, it is just the way how I want to write my code.
+
* Se crea un mapa de bits (bitmap) y se establece como la página de control del mismo tammaño.
* With ''MyPrinter.BeginDoc'' you start printing, however nothing is sent to the printer until you finish with ''MyPrinter.EndDoc;''.
+
* Para evitar imprimir el borde, se establece a off el estilo de borde '''BorderStyle''' antes de dibujar en el bitmap y se vuelve a reestablecer después.
* The printer uses a Canvas to draw the output on. It is this drawing that ends up on the page. ''Canvas.Font'' is the font object for that moment. That is, the ''TextOut'' call we use later will output text using the settings of the font object of that moment.
+
* Then printing is started and the ''BitMap'' canvas content is copied to the printer canvas. But notice one thing, in the process ''page'' is magnified. The '''Printer.papersize''' is considerably bigger than the the size of the bitmap, but the copy process fills the destination rectangle nicely. Por tanto, cuando necesitamos hacer esto, debemos asegurarnos de tener las dimensiones de la página  (''page'') con el mismo ratio que las dimensiones del papel. Puedes imaginarte como hacer esto.
* Everything you draw on the canvas must be positioned using coordinates. So, we calculate a ''LineHeight'' to position text vertically. You could do the same for the horizontal position, which I left here to be ''LEFTMARGIN''.
 
* The text is drawn with the ''TextOut'' call.
 
* This magnificent result is sent to the printer by MyPrinter.EndDoc.
 
  
In some forums it is suggested that the use of ''PrintDialog'' (the printer selection dialog) is required for good functioning, but I did not find this to be true (any more).
+
Un problema relativo a esto es desde luego que los píxeles mostrados en la pantalla se sacarán por la impresora. Como se ha dicho, no es ideal pero muestra el principio de funcionamiento. Los controles no tienen su propio canvas, para imprimirlos primeramente es necesario dibujarlos en un objeto que tenga su propio canvas TBitMap.
 +
Ahora que ya sabes como funciona todo esto ya te puedes imaginar como hacer creaciones artísticas o documentos. Esto requerirá de objetos que se dibujen a sin mismos adecuadamente en un TPanel de baja resolución, pero también un TBitMap con alta resolución, pero esto ya es materia para otro artículo.

Latest revision as of 08:22, 4 March 2020

Deutsch (de) English (en) español (es) 日本語 (ja) 中文(中国大陆)‎ (zh_CN)

Introducción

La impresión es fácil en FreePascal, pero solamente después de seguir algunos pasos requeridos, una vez que se comprenden estos primeros pasos ya se estaría en condiciones de pasar a conceptos más avanzados de impresión. Este artículo trata dichos pasos, que han sido recogidos de varios foros y ejemplos. Después de explicar los pasos básicos se realizará la impresión de unos textos para a continuación plantear sugerencias sobre impresión avanzada.

Los pasos básicos

Se necesita seguir los siguientes pasos para poder utilizar las impresoras:

  1. Añadir el paquete Printer4Lazarus a los requerimientos del programa.
  2. Añadir la unit Printers a la sección uses en la unidad.
  3. Utilizar el objeto existente Printer.

Añadiendo el paquete Printer4Lazarus a los requerimientos del proyecto

El paquete Printer4Lazarus define una impresora básica y provee de un sistema de impresión independiente de la plataforma utilizada. Lo siguiente puede utilizarse por tanto en varias plataformas:

En el IDE de Lazarus, realizar lo siguiente:

  1. En el menú, dentro de Proyecto, haz click en Inspector de Proyecto. A continuación se muestra una ventana con una vista en árbol, una de sus ramas se llama Paquetes Requeridos. Por defecto la rama de Paquetes Requeridos muestra el paquete LCL.
  2. Hacer click en el pulsador Añadir, es el que tiene dibujado el signo +.
  3. Abre la solapa Nuevo requerimiento.
  4. En el cuadro de listado Nombre de Paquete selecciona Printer4Lazarus.
  5. Haz click en Crear Nuevo Requisito.
  6. Con esto ya se muestra Printer4Lazarus en la rama de Paquetes Requeridos.

Añadiendo la unidad Printers a la sección uses section de tu unidad

Esto es simple y fácil de hacer, pareciéndose el resultado a esto:

unit MainUnt;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, Forms, Printers;

Utilizando el objeto Printer

Asumiremos que se necesita un pulsador para imprimir un texto. Dicho pulsador se llama PrintBtn y precisa del evento OnClick, una vez hecho esto ya lo podemos utilizar.

procedure TForm1.PrintBtnClick(Sender: TObject);
const
  LEFTMARGIN = 100; {margen izquierdo, lo definimos como una constante}
  HEADLINE = 'Mi primera impresión de texto utilizando Lazarus '; {Línea de cabecera a imprimir}
var
  YPos, LineHeight, VerticalMargin: Integer; {Posición Y, Alto de línea, Margen vertical }
  SuccessString: String;
begin
  with Printer do
  try { realiza la prueba por si se puede imprimir, caso de que no se realiza una acción, caso de que si realiza finally }
    BeginDoc;   { Comenzamos el documento a imprimir }
    Canvas.Font.Name := 'Courier New'; { Ya tenemos el Canvas pues a llenarlo, en este caso definimos el nombre de la fuente }
    { para el texto que vamos a imprimir }
    Canvas.Font.Size := 10; { Definimos el tamaño para el tipo de fuente (nombre de la fuente) de texto que hemos escogido }
    Canvas.Font.Color := clBlack; { Definimos el color que va a tener nuestra fuente de texto gráfica }
    LineHeight := Round(1.2 * Abs(Canvas.TextHeight('I'))); { Definimos la altura de cada línea }
    VerticalMargin := 4 * LineHeight; { Definimos el margen vertical }
    { una vez hecho lo anterior ya podemos ubicar nuestro texto en el lienzo }
    YPos := VerticalMargin; { Definimos la posición Y en el lienzo }
    SuccessString := HEADLINE + DateTimeToStr(Now);  { Concatenamos nuestro texto de cabecera con la fecha actual } 
    Canvas.TextOut(LEFTMARGIN, YPos, SuccessString); { Escribimos nuestro texto donde lo queremos poner }
  finally
    EndDoc; { Como ya tenemos el lienzo dibujado con nuestro texto, con EndDoc lo enviamos a imprimir }
  end;
end;

Con esto hemos escrito algo basico y simple. El siguiente ejemplo es algo más complejo. Next to the basic text output in the bold line, it also provides an example of formatting your text.

Desde begin a end; sucede lo siguiente:

  • Se puede utilizar el objeto Printer directamente como en el ejemplo anterior, sin utilizar tu propia variable, o como utilizaremos en el siguiente ejemplo con con MiImpresora. Por lo tanto el objeto MiImpresora no es realmente necesario, se ha utilizado para dar claridad al código fuente utilizado.
  • Se comienza la preparación de impresión con MiImpresora.BeginDoc pero todavía no se envía nada a la impresora, por lo que podemos ir rellenando en unas coordenadas de ubicación sobre el lienzo (Canvas) el texto deseado con una tipografía, un color,....hasta que se finalice el bloque con MiImpresora.EndDoc;.
  • Printer utiliza un lienzo (Canvas) para dibujar sobre el mismo el contenido tal como lo haríamos en una hoja de papel (bien sea texto (con su tipografía, formato, color....), líneas, dibujos, etc). Para ir rellenando el lienzo anteponemos Canvas seguido de un punto (Canvas.) luego que que deseamos poner, en este caso al ser texto lo primero que hacemos es establecer la tipografía con Canvas.Font, por lo tanto ya hemos puesto un objeto tipo font. Ponemos otro punto (Canvas.Font.) y por tanto dentro de font podemos definir la tipografía por su nombre (Canvas.Font.Name) que en este caso lo establece a Courier New, pero podríamos establecer su tamaño (Canvas.Font.Size) o su color (Canvas.Font.Color) o cualquiera otra propiedad que ese objeto nos permita establecer.

Una vez definido esto con TextOut escribimos nuestro texto en el lienzo.

  • Todo lo que se dibuja en un lienzo (canvas) debe posicionarse utilizando coordenadas (podeis imaginarlo como un papel milimetrado donde en unas coordenadas de partida ubicais un objeto (texto en nuestro caso pero podría haber sido una foto, un dibujo con líneas...). Como en este caso se trata de texto nos interesa definir la altura de la línea LineHeight. Se puede hacer lo mismo para la posición horizontal, en este caso estableciendo el valor del margen izquierdo LEFTMARGIN.
  • Una vez establecido todo lo anterior ya podemos escribir el texto en el lienzo mediante la llamada aTextOut.
  • Con el lienzo dibujado a nuestro gusto solamente nos resta enviarlo a la impresora y para ello utilizamos MiImpresora.EndDoc.

En algunos foros se sugiere que para un correcto funcionamiento se utilice el diálogo PrintDialog pero no he encontrado que esto sea necesario (obligatorio) en ningún caso.

Siguientes pasos

Después de realizar los pasos anteriores ya podemos avanzar más en los siguientes, dejando al lector otras pruebas como:

  • Realizar el dibujo en papel.
  • Formatear el texto de forma agradable.
  • Seleccionar otra impresora y comparar los resultados.

En la distribución Lazarus se incluye un proyecto de ejemplo que utiliza un Raw para imprimir a la impresora. Se puede encontrar este ejemplo en la siguiente ubicación (en windows) C:\lazarus\components\printers\samples\rawmode\rawmodetest.lpi. En otro ejemplo se muestra como seleccionar otra impresora, lo podéis encontrar en C:\lazarus\components\printers\samples\dialogs\selectprinter.lpi.

Pasos avanzados

El objeto printer permite primariamente dibujar en un lienzo (canvas) y enviar esta imagen a la impresora. Si continuamos en la senda ya mostrada, entonces se puede utilizar el método canvas para dibujar texto, elipses, rectángulos o cualquier otra cosa que se nos ocurra. Esto se muestra ya sumamente interesante para cualquier programador serio. Por ejemplo si estás trabajando en un programa de CAD más perfeccionado o en algún organizador de imágenes y quieres imprimir el estupendo resultado en el lienzo (canvas), entonces tratar de plasmar ese resultado mediante llamadas al lienzo no es el camino ya que directamente se tiene el cuadro.

Todos y cada uno de los controles que se emplazan en el formulario también dibujan una imagen en un objeto TCanvas tal como el de la impresora (printer). Imagínate que estás tratando de implementar un programa de visualización preliminar. Primeramente creas un formulario y dentro de él pones un TPanel, el cual aporta el agradable fondo grisaceo de la vista previa. En este panel pones otro objeto TPanel llamado page. Esta page será de color blanco y representará el papel. En esta página se puede poner un objeto TSahpe, por ejemplo un vistoso rectánculo redondeado rojo. A continuación prueba lo siguiente en el evento PrintBtnClick del método:

MiImpresora.BeginDoc;
  page.PaintTo(MiImpresora.Canvas, 0, 0);
MiImpresora.EndDoc;

Esto es lo que sucede:

  • BeginDoc comienza la impresión del documento, o composición (pero no se envía todavía nada a la impresora).
  • page.PaintTo envía la salida de nuestro objeto TPanel al lienzo (que representa la página) de la impresora. Fíjate en lo siguiente:
    1. Puedes utilizar el método PaintTo de cualquier control en la jerarquía de controles. Puedes además enviar la salida de la ventana completa a printer si lo necesitas.
    2. Puedes enviar la salida de cualquier control a printer con el método PaintTo. Para enviar la salida de tu organizador de imágenes a la impresora puedes enviar la salida de TImage a la impresora.
    3. TCanvas también tiene un método para copiar rectángulo desde otro canvas. Sin embargo, solo se puede hacer si un objeto dibuja realmente a un lienzo (canvas). Creo que la mayor parte de los controles recaen en contenedores para proveer de un canvaas real, por lo tanto no puedes copiar rectángulos desde cualquier control. Al menos esto no me han funcionado a mí.
    4. Asegúrate de que el control que necesitas dibujar a la impresora está visible. Si el control no es visible entonces no se pintará nada ni siquiera a la impresora.
  • EndDoc envía lo dibujado a la impresora seleccionada.....

Avanzando más contenido

La impresora utiliza muchos más pixeles por pulgada (ppi: pixeles per inch) en su impresión en papel que los utilizados por un monitor para representar la misma información en pantalla. Como resultado, la salida que es redirigida desde la pantalla a la impresora aparece más pequeña cuando es impresa en papel. Es por tanto importante el escalando y control de la disposición para una buena salida impresa. Sería agradable si se pudiese obtener una salda impresa de tamaño exactamente igual a lo mostrado en pantalla.

Por el momento no nos estamos esforzando por el idea, solamente por la idea. Como se dijo anteriormente, los controles no tienen su propio lienzo (canvas) pero recaen en el lienzo (canvas) de un contenedor o dueño. Sin embargo, existen componentes que tienen su propio lienzo (canvas). Yo escogí TBitMap y funcionó como sigue:

procedure TForm1.PrintBtnClick(Sender: TObject);
var
  MiImpresora : TPrinter;
  MiMapadeBits : TBitMap;
begin
  MiMapadeBits := TBitMap.Create;     { Creamos el objeto MiMapadeBits }
  MiMapadeBits.Width := page.Width;   { Definimos su anchura }
  MiMapadeBits.Height := page.Height; { Definimos su altura } 
  page.BorderStyle:=bsNone; { Definimos el estilo del borde a ninguno }
  page.PaintTo(myBitMap.Canvas, 0, 0); 
  page.BorderStyle:=bsSingle;
  //
  MiImpresora := Printer;
  MiImpresora.BeginDoc;
    //page.PaintTo(MiImpresora.Canvas, 0, 0);
    //MiImpresora.Canvas.Draw(0,0, myBitMap);
    MiImpresora.Canvas.CopyRect(Classes.Rect(0, 0, MiImpresora.PaperSize.Width, MiImpresora.PaperSize.Height),
       myBitMap.Canvas, Classes.Rect(0, 0, myBitMap.Width, myBitMap.Height));
  MiImpresora.EndDoc; { Damos por finalizada la composición y enviamos el contenido del lienzo a la impresora }
  MiMapadeBits.Free;  { Liberamos el recurso MiMapadeBits de la memoria }
end;

Para este trabajo no utiliceis la unit Windows. La unit Windows tiene otras definiciones para Rect. La descripción dedel código paso a paso del ejemplo anterior es la siguiente:

  • Se crea un mapa de bits (bitmap) y se establece como la página de control del mismo tammaño.
  • Para evitar imprimir el borde, se establece a off el estilo de borde BorderStyle antes de dibujar en el bitmap y se vuelve a reestablecer después.
  • Then printing is started and the BitMap canvas content is copied to the printer canvas. But notice one thing, in the process page is magnified. The Printer.papersize is considerably bigger than the the size of the bitmap, but the copy process fills the destination rectangle nicely. Por tanto, cuando necesitamos hacer esto, debemos asegurarnos de tener las dimensiones de la página (page) con el mismo ratio que las dimensiones del papel. Puedes imaginarte como hacer esto.

Un problema relativo a esto es desde luego que los píxeles mostrados en la pantalla se sacarán por la impresora. Como se ha dicho, no es ideal pero muestra el principio de funcionamiento. Los controles no tienen su propio canvas, para imprimirlos primeramente es necesario dibujarlos en un objeto que tenga su propio canvas TBitMap. Ahora que ya sabes como funciona todo esto ya te puedes imaginar como hacer creaciones artísticas o documentos. Esto requerirá de objetos que se dibujen a sin mismos adecuadamente en un TPanel de baja resolución, pero también un TBitMap con alta resolución, pero esto ya es materia para otro artículo.