2 formas de imprimir un formulario en C#

Tamaño de letra:

Cómo imprimir  un formulario en C#

Imprimir formulario en C#A diferencia de Visual Basic .NET que tiene el componente PrintForm (puede imprimir, en tiempo de ejecución, una imagen de un formulario de Windows) y ahorra bastante código, en C# hay que hacerlo a mano siguiendo un proceso que resulta muy sencillo de entender. Te voy a mostrar 2 formas diferentes de hacerlo y cuál de los dos da como resultado una mejor calidad final:

1.- Imprimiendo el formulario realizando primeramente una captura del mismo.
2.- Dibujando previamente todos los controles uno a uno.

El componente PrintForm de VB te habilita para imprimir rápidamente una imagen de un formulario tal y como aparece en pantalla sin usar un componente PrintDocument.

1.- Imprimir imagen del formulario

Esta es la forma más sencilla y comentada en la Red. Hay que seguir los siguientes pasos:

  1. Capturar una instantánea del formulario y convertirla en una imagen Bitmap.
  2. Dicho bitmap dibujarlo en un documento
  3. Abrir cuadro de diálogo para seleccionar impresora
  4. Mostrar, si se quiere, una vista previa
  5. Imprimir el documento

Antes de ponerte todo el código, voy a ir explicando cada parte:

1.1 - Capturar instantánea del formulario

Puedes hacerlo con este sencillo código:

 
private void CapturaFormulario()
        {
            Size sz = this.Size;
            bmp = new Bitmap(sz.Width, sz.Height, PixelFormat.Format32bppRgb);
            Graphics memoryGraphics = Graphics.FromImage(bmp);
            memoryGraphics.CopyFromScreen(this.Location.X, this.Location.Y, 0, 0, sz,
                                          CopyPixelOperation.SourceCopy);
 
            //bmp.Save("prueba.bmp", ImageFormat.Bmp);
        }
 

Si quitas el comentario de la última línea y guardas la imagen, el resultado será el siguiente:

Captura formulario con CopyFromScreen

Este ejemplo tiene el problema de que la imagen a capturar tiene que estar arriba de todas y, en algunos casos, deberás esperar unos milisegundos para que de tiempo a cerrar la que esté sobre ella (por ejemplo, la de selección de impresora). También puedes ver que captura toda la ventana completa.

Esta otra forma la he obtenido de un código visto en microsoft.com:

 
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
        public static extern long BitBlt(IntPtr hdcDest, int nXDest, int nYDest,
                                         int nWidth, int nHeight, IntPtr hdcSrc,
                                         int nXSrc, int nYSrc, int dwRop);
 
private void CapturaFormulario()
        {
            Graphics mygraphics = this.CreateGraphics();
            Size sz = this.ClientRectangle.Size;
            bmp = new Bitmap(sz.Width, sz.Height, mygraphics);
            Graphics memoryGraphics = Graphics.FromImage(bmp);
            IntPtr dc1 = mygraphics.GetHdc();
            IntPtr dc2 = memoryGraphics.GetHdc();
            BitBlt(dc2, 0, 0, this.ClientRectangle.Width,
                   this.ClientRectangle.Height, dc1, 0, 0, 13369376);
            mygraphics.ReleaseHdc(dc1);
            memoryGraphics.ReleaseHdc(dc2);
 
            //bmp.Save("prueba.bmp", ImageFormat.Bmp);
        }
 

13369376(decimal) = CC0020(hex) = SRCCOPY: Copia el rectángulo de origen directamente en el rectángulo de destino.

Más precisa, y el resultado es:

Captura formulario con BitBlt

1.2 - Dibujar el bitmap en un documento a imprimir

Para poder imprimir necesitamos crear un documento y pegar en él todo lo que queramos imprimir. El control PrintDocument es el documento que buscamos. La forma más sencilla de dibujar el bitmap posiblemente sea esta:

e.Graphics.DrawImage(bmp, 0, 0);

Sin embargo, haciéndolo de este modo podemos tener un problema de ajuste de escala. Esto se produce por las diferencias de resolución utilizadas por GDI+ y el objeto Image. Para evitar este comportamiento y mejorar el rendimiento del código, el método DrawImage lo dejo así:

e.Graphics.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height);

1.3 - Seleccionar impresora

Para la selección de la impresora se utiliza PrintDialog:

private PrintDialog Impresora = new PrintDialog();
...
DialogResult Result = Impresora.ShowDialog();

1.4 - Mostrar vista previa

Si quieres puedes mostrar una vista previa:

PrintPreviewDialog VistaPrevia = new PrintPreviewDialog();
...
VistaPrevia.ShowDialog();

1.5 - Imprimir el documento

Es muy sencillo invocando al método Print:

private PrintDocument DocumentoParaImprimir = new PrintDocument();
...
DocumentoParaImprimir.Print();

El método Print produce el evento PrintPage, que es donde pegamos la imagen en el documento.

Todo el código

Para que no tengas que crear nada he intentado hacer un ejemplo con todo incluido. Solamente debes crear un nuevo proyecto y pegar este código:

 
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
 
namespace imprimirCaptura
{
    public partial class Form1 : Form
    {
        private Button btImprimir;
        private Button btVistaPrevia;
        private PrintDocument DocumentoParaImprimir = new PrintDocument();
        private PrintDialog Impresora = new PrintDialog();
        private PrintPreviewDialog VistaPrevia = new PrintPreviewDialog();
        private Bitmap bmp;
 
        public Form1()
        {
            this.btImprimir = new System.Windows.Forms.Button();
            this.btImprimir.Location = new System.Drawing.Point(20, 20);
            this.btImprimir.Size = new System.Drawing.Size(100, 30);
            this.btImprimir.Text = "Imprimir";
            this.btImprimir.Click += new System.EventHandler(this.btImprimir_Click);
            this.Controls.Add(this.btImprimir);
 
            this.btVistaPrevia = new System.Windows.Forms.Button();
            this.btVistaPrevia.Location = new System.Drawing.Point(20, 60);
            this.btVistaPrevia.Size = new System.Drawing.Size(100, 30);
            this.btVistaPrevia.Text = "Vista Previa";
            this.btVistaPrevia.Click += new System.EventHandler(this.btVistaPrevia_Click);
            this.Controls.Add(this.btVistaPrevia);
 
            DocumentoParaImprimir.PrintPage +=
                new PrintPageEventHandler(DocumentoParaImprimir_PrintPage);
        }
 
        void DocumentoParaImprimir_PrintPage(object sender, PrintPageEventArgs e)
        {
            e.Graphics.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height);
        }
 
        private void btImprimir_Click(object sender, EventArgs e)
        {
            CapturaFormulario();
 
            Impresora.Document = DocumentoParaImprimir;
            DialogResult Result = Impresora.ShowDialog();
 
            if (Result == DialogResult.OK)
            {
                DocumentoParaImprimir.DefaultPageSettings.Landscape = false;
                DocumentoParaImprimir.Print();
            }
        }
 
        private void btVistaPrevia_Click(object sender, EventArgs e)
        {
            CapturaFormulario();
 
            VistaPrevia.Document = DocumentoParaImprimir;
            VistaPrevia.ShowDialog();
        }
 
        private void CapturaFormulario()
        {
            Graphics mygraphics = this.CreateGraphics();
            Size sz = this.ClientRectangle.Size;
            bmp = new Bitmap(sz.Width, sz.Height, mygraphics);
            Graphics memoryGraphics = Graphics.FromImage(bmp);
            IntPtr dc1 = mygraphics.GetHdc();
            IntPtr dc2 = memoryGraphics.GetHdc();
            BitBlt(dc2, 0, 0, this.ClientRectangle.Width,
                   this.ClientRectangle.Height, dc1, 0, 0, 13369376);
            mygraphics.ReleaseHdc(dc1);
            memoryGraphics.ReleaseHdc(dc2);
 
            //bmp.Save("prueba.bmp", ImageFormat.Bmp);
        }
 
        [System.Runtime.InteropServices.DllImport("gdi32.dll")]
        public static extern long BitBlt(IntPtr hdcDest,
            int nXDest,
            int nYDest,
            int nWidth,
            int nHeight,
            IntPtr hdcSrc,
            int nXSrc,
            int nYSrc,
            int dwRop);
    }
}
 

Este código funciona correctamente pero según las pruebas que he realizado, el resultado de la impresión no es muy nítido y las etiquetas (labels) quedan algo borrosas. Tal vez sea por el contraste de colores o por la resolución del bitmap a 96 píxeles por pulgada, pero si comparas dicha impresión con el texto de un libro o con un documento imprimido desde Word, hay muchísima diferencia. Después de los resultados obtenidos, yo no usaría dicho código en un proyecto donde necesites una buena calidad final.

Para mejorar la nitidez y que se vea correctamente, puedes recurrir a dibujar uno a uno los controles del formulario en el documento a imprimir como se explica a continuación:

2.- Dibujar previamente los controles uno a uno

Como encontré este excelente código: imprimir un formulario usando API, no veo necesario reescribirlo porque es muy completo. El código es muy interesante, está incorporado en un archivo PrintForm.cs y para imprimir un formulario solo debes llamarlo del siguiente modo:

PrintForm pf = new PrintForm(this);
pf.Print();

Puedes realizar, modificando el código, ajustes antialisis o editar propiedades para mejorar la calidad. Personalmente esta segunda opción de dibujar uno a uno los controles es mucho más precisa y nítida. Es similar a cuando tenemos un documento de texto y antes de realizar la impresión, llamamos a e.Graphics.DrawString para dibujar en el documento el texto.

El código, funciona bastante bien y calcula las medidas del texto (o controles) para imprimirlas en otra página si sobrepasan las dimensiones, sin embargo, hay que retocarlo para que no dibuje la barra de título o para que deje elegir la impresora a utilizar (esto no es nada difícil). Pero la idea y el resultado final son excelentes.

Después de analizar y probar el código más detenidamente hay cosas de él que no me gustan. Por ejemplo, los textos son centrados verticalmente "a mano" y solo se pueden alinear a la izquierda. Esto tiene fácil solución usando:

StringFormat FormatoTexto = new StringFormat();
FormatoTexto.Alignment = StringAlignment.Center;
FormatoTexto.LineAlignment = StringAlignment.Center;

Última actualización: Sábado, 17 Agosto 2013
Comentarios  
0 # ariel 20-11-2019 21:36
Cito a karmany:
No entiendo a qué te refieres exactamente.

:-x :-x :-x :-x :zzz
Responder | Responder con una citación | Citar
+1 # Map 06-11-2019 21:00
Alguien me ayudaria a imprimir el formulario? osea imprimir lo que sale o se ingresa en el formulario?
Responder | Responder con una citación | Citar
+1 # karmany 06-11-2019 22:40
No entiendo a qué te refieres exactamente.
Responder | Responder con una citación | Citar
+1 # Alfredo 20-10-2018 04:50
Quiero imprimir ticket de una tienda q lo imprima varias veces cual me recomiendas mas sencillo?
Responder | Responder con una citación | Citar
+1 # Editor 21-10-2018 12:14
Ha pasado tiempo desde este tutorial, no sé si existirá alguna nueva forma.

Yo recuerdo usar la segunda forma porque la impresión es de muchísima más calidad. Recuerdo también modificar el código para ajustar perfectamente todos los controles, pero esto es hacer pruebas. La primera forma es muy sencilla e incluso se puede optimizar más (según he visto en Microsoft) pero el resultado no tiene buena calidad.
Responder | Responder con una citación | Citar
+1 # cecilia 14-02-2015 20:04
Imprimir en C# es de lo PEOOORR, necesito imprimir sobre un formulario ya impreso y ubicar cada dato en su casilla correspondiente me esta enloqueciendo, podria ser mas facil....
Responder | Responder con una citación | Citar
+1 # Alfredo 14-02-2015 23:11
Tienes razón. En mi proyecto yo utilicé lo que se comenta en este artículo como segunda forma. Mira el enlace, una vez que lo entiendes es muy sencillo y el resultado de calidad.
Responder | Responder con una citación | Citar
-1 # limbert 13-03-2014 16:08
hola, como puedo hacer para guardar a un archivo word o un pdf.... ayuda..
Responder | Responder con una citación | Citar
-1 # karmany 13-03-2014 18:51
¿Guardar en un word o pdf el formulario que se ha imprimido?
¿Quieres guardar el formulario en un pdf o formato de word?
Responder | Responder con una citación | Citar
-1 # Anon 20-10-2014 06:28
Precisamente eso! quiero, (si es posible) generar un word especifico de acuerdo a valores que lei en un textbox y luego imprimir, no es necesario que sea un word!!
Responder | Responder con una citación | Citar
-1 # Aitor 20-10-2014 11:27
Pero eso es otro tema te refieres a exportar el contenido de un textbox a word. Busca cómo exportar a world.
Responder | Responder con una citación | Citar
-1 # limbert 13-03-2014 15:03
ayudaaa ..
me sale error en el PixelFormat "que tendriera que agregar un using o que ??"
Responder | Responder con una citación | Citar
-1 # karmany 13-03-2014 18:54
Tienes que indicar el error.
¿Cuál es el error exacto que te aparece?
Responder | Responder con una citación | Citar
Escribir un comentario
Antes de publicar un comentario, usted debe aceptar nuestras condiciones de uso: Condiciones de uso. Debido al spam, todos los comentarios serán moderados. Normalmente se responde en unos minutos, refresca los comentarios para comprobarlo.



 
Visitas: 8495854