09 mayo 2011

Impresiones con Visual Basic 2010

PrinterPese a que vivimos en una era digital y todo (bueno, casi todo) se hace por internet y con la computadora, aún hay momentos en que el papel es necesario.  Hace tiempo escribí un post donde indicaba cómo imprimir usando Visual Basic 6, pero no había tenido la oportunidad de hacer lo mismo con el Visual Basic .net.  Y eso precisamente es lo que pienso hacer en esta ocasión: mostrar como usar los controles y cajas de diálogo para imprimir y la forma de imprimir tanto texto como imágenes.
Antes de continuar con rollo, código, ejemplos y demases, voy a describir brevemente los componentes que tiene Visual Basic 2010 para imprimir.
Control PrintDocument
Este control se debe agregar a cualquier proyecto en el que se quiera imprimir algo.  Haz de cuenta que es la hoja en blanco donde puedes dibujar diferentes objetos, escribir texto y colocar imágenes de mapa de bits.  Cuando acabes de dibujar, escribir, etc., se llama el método Print para que la impresora escupa la hoja.  Acepta todos los métodos de dibujo que usa el objeto Graphics (mismo del que di ejemplos aquí y aquí), es decir que si tienes que escribir texto, usas el método DrawString; si quieres dibujar un marco alrededor del texto, puedes usar DrawLine o DrawRectangle.  Aunque el control es invisible (no aparece en la ventana ni hay forma de ir viendo conforme se va dibujando), es muy útil.
Control PrintDialog
Este control hace aparecer la ventana default que te permite elegir y configurar la impresora que se desea emplear.  Si no se usa, la impresión se hace en la impresora que se tiene definida como default con las propiedades que trae por default (o sea con lo default de lo default Sonrisa).  Para que aparezca, se debe usar el método ShowDialog.
Control PageSetupDialog
Este control hace aparecer la ventana que te permite configurar el papel a usar: tamaño, orientación, márgenes, etc.  Se debe usar su método ShowDialog para que aparezca, igual que con el control PrintDialog.
Control PrintPreviewDialog
Este control hace aparecer una vista previa de lo que se va a imprimir.  Como mostraré más adelante, se debe vincular este control con lo el control PrintDocument para que todo lo que se va a imprimir, en lugar de ir a la impresora, aparezca en esta ventana.  También hay que tener cuidado: si no se tiene acceso a la impresora que está seleccionada (por ejemplo, una impresora de la red a la cual no tengo acceso en este momento o la que tengo conectada está apagada), no aparece la ventana y te marca error.  Es necesario recibir este error (con un Try…Catch) para que no termine abruptamente el programa solo porque no halla la impresora (cosa que no hago en este post, por cierto).
Ejemplo de su uso
Después de este rollo (que espero que haya sido breve), voy a ejemplificar el uso de estos controles en un programa que hice con mis queridísimos alumnos de 4TPO.  Es un ejemplo muy simple que solo muestra como se usan los controles.  Sin embargo, creo que con estas bases ya le pueden echar vuelo a la imaginación para aplicarlo en otros contextos.
Antes que nada, les muestro el diseño de la ventana principal.  Consta de 3 etiquetas, 3 cajas de texto (txtNombre, txtDir y txtRFC), un PictureBox (picCanoa) que sirve para mostrar como imprimir una imagen de mapa de bits, 7 botones cuyo código explicaré más adelante, 2 controles PrintDocument, un PrintDialog, un PageSetup y un PrintPreviewDialog.  Estos 5 últimos no aparecen en la ventana: cuando los agregas a la ventana aparecen en la parte inferior.
00Form1
Para que un PrintDocument funcione, es necesario editar su evento PrintPage.  Si le das doble clic al icono PrintDocument1, verás este código:
01PrintDocument1
Básicamente uso el parámetro e, que es “la hoja invisible” sobre la que voy a dibujar, para escribir 3 cadenas, un rectángulo y la imagen de la canoa.  Como mencioné con anterioridad, son las mismas funciones que se usan para dibujar gráficos sobre la ventana cosa que ya escribí en este post y en este también.
Una vez que tienes este evento listo, puedes mandar imprimir con la función Print.  Yo lo hago con el botón cuya etiqueta dice Imprimir y este es el código:
02btnImprimir
El PrintDocument2 muestra una idea para imprimir formatos.  Dibujé el esqueleto de un formato, lo guardé como PNG, lo importé a Visual Basic y lo puse en un PictureBox (llamado PictureBox1) en la ventana frmPicts.  Aquí está la ventana frmPicts y abajo el código que lo usa (primero el el botón que tiene la etiqueta Imprimir formato, btnImprime2, y luego PrintPage).
03frmPicts
04PrintDocument2
Configurar la impresora es muy simple usando el control PrintDialog.  Este es el código del botón con la etiqueta Configurar impresora.  Fíjate en la manera en que copio las propiedades puestas por el usuario en este cuadro de diálogo en los dos controles PrintDocument (en las 2 últimas instrucciones):
ConfigImpr
A la hora de ejecutarse, el control PrintDialog hace que aparezca esta ventana:
06PropImpresora
También es sencillo modificar la configuración de la página.  Este es el código del botón etiquetado Configurar página:
07btnConfPag
Antes del ShowDialog es necesario igualar sus propiedades a los que ya tiene un PrintDocument (en las dos instrucciones que siguen al comentario).  Al correr este evento, aparece esta ventana:
08ConfPag
Una vista previa (o presentación preeliminar) de lo que se va a imprimir suele ser bastante útil para muchos usuarios.  Hacer que aparezca es sencillísimo.  Lo único que hay que hacer es hacer que, en lugar de que el evento PrintPage de un PrintDocument lo mande a la impresora, se le envía a esta caja de diálogo.  Abajo pongo el código y luego la ventana que aparece que muestra la vista preeliminar:
09btnVistaPrev
10VistaPrevia
También es posible jugar con la configuración de la impresora.  Para leer algunas propiedades de las impresoras, hice el botón etiquetado Lista de impresoras que abre la ventana frmImpresoras desde donde se pueden ver la lista de impresoras instaladas y al seleccionar una de ellas, se ven algunas de sus propiedades.  Esta es la ventana frmImpresoras en la vista diseño:
11frmImpresoras
Tiene una lista donde voy a escribir la lista de impresoras (ListBox1), etiquetas que muestran los valores de las copias, si es duplex (si puede imprimir por ambas caras de la hoja), el número máximo de copias permitidas y si puede recibir documentos a color (lblCopias, lblDuplex, lblCopiasMax y lblColor, respectivamente).  También es necesario un PrintDocument para poder ver estas propiedades.  Pero antes que nada, veamos el código con que llena ListBox1:
12frmImpresoras
Nótese que estoy haciendo uso de la colección Printing.PrinterSettings.InstalledPrinters misma que contiene la lista de todas las impresoras instaladas en el equipo donde se está ejecutando.  Estoy usando la instrucción With para abreviar un poco y no escribir este rollo a cada rato.
No necesito escribir un evento PrintPage para el PrintDocument1 porque no voy a imprimir nada: solo lo necesito para poder mostrar las propiedades.  Por esta razón el otro código interesante es el que se ejecuta cuando ListBox1 cambia de elemento seleccionado:
13ListBox1
Este es un ejemplo de como se ve esta ventana con una impresora seleccionada:
14frmImpresoras
Espero que este documento te sea útil.  ¡Hasta la próxima!
P.D. La imagen que usé de la impresora verde fue hecho por OCAL.  De gran ayuda para elaborar este post fue el siguiente libro:

55 comentarios:

Urban Rider dijo...

Que onda Tony!
Que crees ando haciendo un programilla para una empresa haha (sigo programando) estaba usando tu articulo :D, creo que hay algo raro, a la hora que dices el codigo para mostrar el PrintDialog, la imagen, segun yo esta mal, por que esa es para el de configurar. y una duda, cuando esta corriendo el programa y haces un preview de lo q vas a imprimir todo muy bien, pero lo cierras el control y le vuelves a pedir otro preview y me dice que el objeto ya esta disposed haha sabes como arreglar eso? Graciass Saludos (:

Tony Valderrama dijo...

¡Peinado! ¡Qué milagro! Que bueno que este blog todavía te sea útil.

Respondiendo a tus preguntas, en efecto el PrintDialog hace que aparezca la ventana que puse. También hay ventanas para configurar márgenes y otros rollos. Este es para configurar la impresora.

Por el otro lado, a mi no me marca error al abrir la vista previa una y otra vez. Lo acabo de probar y lo abrí y cerré 4 veces, una tras otra, y no me marca error. ¿Qué VB estás usando? Yo lo estoy corriendo con el 2010...

eshu oni bodde dijo...

muy chevre esto tony pero el problemita mi es q es una factura sabes lleva tanto texbox como label como hago para q me enseñe todo eso ya q con la tuya e cuadraro dos cosas nada mas ya q segun las cordenadas q pusiste tu las enseña como en tu figura me gustaria me ayudaras

Tony Valderrama dijo...

Estimado eshu oni bodde:

No entiendo exactamente a que te referes. Si es que tienes texto en un label y en un textbox, solo hace poner Text1.Text (o como se llame) en el e.DrawString().

Si es que es demasiado texto, yo generalmente uso un ciclo que va imprimiendo renglón por renglón, cambiando las coordenadas verticales en cada línea que imprimo.

No sé si te resuelva tu duda o te dejé en las mismas...

eshu oni bodde dijo...

me gustaria que me ayudaras e seguidos tus pasos y perfecto el gran detalle es que lo logro poner a lo ancho pero el espacio entre linea y linea si se pudiera decir asi es el q o consigo ese pedasito de codigo es el q no se....ya q tu me diste este Text1.Text (o como se llame) en el e.DrawString(). con ese los puedo colocar a lo ancho pero para separar entre ellos cual es...de verdad telo sabria agradecer

eshu oni bodde dijo...

ok tony todo esto en visual studio 2010 de verdad mil gracias por tus consejos

Tony Valderrama dijo...

Estimado eshu oni bodde:

Creo que ese código no debería quitarte el sueño. Voy a escribir algo medio en pseudocódigo medio en VB a ver si despeja tus dudas...

Renglon=1600
Do While (todavía no acabo de imprmir)
e.DrawString(El renglón de texto,300,Renglon)
Renglon+=50
Loop

Donde la coordenada del renglón donde se imprimirá en la hoja comienza en 1600 (por inventarme un valor) y aumentará de 50 en 50. También 300 la estoy dejando como la coordenada X: siempre imprime en la misma posición en X.

¿Algo así es lo que necesitas?

eshu oni bodde dijo...

tony yo tengo este codigo:
private sub printdocument1_printpage(byval sender as system.object, byval e as system.drawing.printing.printpageeventargs) handles printdocument1.page

e.graphics.drawstring(lblnfctura.text, lblnfactura.font, brushes.black,400,50)
colocando lo asi querido amigo toni me da perfectamente las cordenadas al ancho de la pagina, como podria introducir el codigo q tu me diste para hacer que el separe las lineas osea que arriba quede numero de factura exquina superio izquierda y la fecha lo coloquemas una linea por debajo de eso...gracias si me puedes explicar

eshu oni bodde dijo...

que onda tony!!!!
me gustaria tu ayuda con ese problemita

Jose Abel Mayorga dijo...

Solamente mi pregunta seria como puedo cargar el formato de fondo de la factura ????

Tony Valderrama dijo...

Estimado José Abel:

Haz tu factura en formato JPG y cárgalo como hice con la imagen de la canoa en mi ejemplo. Solo cambia las coordenadas donde lo posiciones.

Puedes escribir el texto encima de la imagen, usando los comando que describí en el ejemplo.

Espero que te sea útil...

Jose Abel Mayorga dijo...

muchisiiimassss gracias =D por tu ayudaaa enserio me as ayudadoooo demasiadooo =D ya pude gracias a ti hehe ya tengo tiempo programando pero nunca paso por mi mente el hacer algo como esto de mandar imprimir desde vb y por pura curiosidad y por aprender decidi hacer algo y gracias por ensenarme hehehe

Jose Abel Mayorga dijo...

oie hahaha disculpa por molestar pero como le puedo hacer para k lo que escribia salga sobre la imagen ya cargue la imagen pero esta sobre las letras como le puedo hacer =P hehehe

Tony Valderrama dijo...

Solo especifica bien las coordenadas del lugar donde quieres que salga el texto... no importa que sea sobre la imagen.

Mucho es a prueba y error. Instala alguna impresora virtual como el que viene con Office o Bullzip PDF Printer porque si imprimes cada prueba, vas a gastar muchísimo papel.

Jose Abel Mayorga dijo...

hahahaha ya pude moviendoleee ya le encontre muchas gracias =P

Jose Abel Mayorga dijo...

si hehe uso el cutePDF para hacerlo aki mismo ya cuando lo tenga listo pongo predeterminada la impresora hehe =P muchas gracias de verdad esto si me sirvio muchisimooooo

Tony Valderrama dijo...

Que bueno que te fue de utilidad.

¡Saludos!

+...SAT...+ dijo...

Hola, muchas gracias por toda la informacion.... Ando checando, como imprimir informacion desde visual, es decir, Tengo un formulario en el que ingreso todo a una base de datos, pero esos mismos datos, necesito imprimirlos en una hoja, como una solicitud de alta a un nuevo empleado.... Tu informacion me dio algunas ideas....

Pero me podrías aconsejar cual es la mejor manera de hacer lo que quiero, o donde puedo encontrar mas informacion con respecto a las herramientas que pusiste???.....

De antemano muchisimas _Gracias_

Jose Abel Mayorga dijo...

hehe pues a como esta el tutorial de tony pues esta muy detallado lo mio es algo similar al tuyo pero lo mio es de factura lo k hice fue escanear la factura y agregarla y empezar a mover los campos seria algo similar pero lo tuyo seria como los datos de empleado y eso perdon por entrometerme xD a como veo pues no se como se llama la barra de navegacion o algo asi cuando enlazas la base de datos a visual de ai pues los grabas y con un boton aparte mandas imprimir los campos k son =P

+...SAT...+ dijo...

Ok muchisimas Gracias, indagaré un poco mas con respecto al tema, haber que sale....

Anónimo dijo...

Compañeros una Consulta estoy desarrollando una aplkicación con Visual Studio 2005 para Windows Mobile, necesito el codigo que me permita imprimir los datos de un formulario....

enviar codigo al melberdc_2000@hotmail.com


El ejemplo de impresion esta muy bueno...... Excelente gracias...

Anónimo dijo...

muy buenos los tutos....una duda...se pueden sdeguir los mismo pasos en visual 2005..???

Tony Valderrama dijo...

Estimado Anónimo: no creo que tengas problemas con el 2005... según yo, debería funcionar igual.

Avísanos si hay algún cambio :)

Anónimo dijo...

OYE AMIGO YO NECESITO UNA GRAN AYUDA, NECESITO IMPRIMIR DATOS DE UNA FACTURA. PERO NO SE COMO CALCULAR LA PARTE EN LA QUE SE DEBE IMPRIMIR AL INGRESAR LA FACTURA.


MAS QUE NADA HACE UN MACHOTE.
PODRIAS AYUDARME.



ESTE ES MI CORREO POR SI TE INTEREZA AYUDARME
isay_15@hotmail.com

Anónimo dijo...

Estimado Tony (se me hace cuesta arriba decirle tony a alguien tan sabio como Vd.):
Durante días me he estado partiendo la cabeza con el tema de la impresión en VB2010. Me encuentro con esta página que está expuesta con una claridad impresionante. A sus alumnos les ha tocado el gordo con tener un profesor con tal claridad de exposición.Yo recuerdo hace años a un profesor que tuve de Análisis Químico, igual. Con él no había cuestiones difíciles, todo lo hacía claro. Para alguien como yho bastante ducho en VB6.0 pero muy poco en VB2010 hay algunas cosillas que tendré que poner más en claro, pero en un 90% todo, chapeau. Muchísimas gracias. Alberto.

Tony Valderrama dijo...

Alberto:

Me da mucho gusto que te haya sido útil esta información. Recibe un fuerte saludo navideño :)

Anónimo dijo...

Saludos Tony, excelente la explicación.

Un saludo desde México

Anónimo dijo...

Hola necesito ayuda para el codigo de como poner un boton para poder escanear

Maria Fraire dijo...

hola que tal me parecio interesanate ahora me gustaria sber como puedo hacer que mi texto que imrpime no imprima junto ...basicamente empalma todo lo que tiene que imprimir ..creo que hay que darle un formato..pero nose como ..Podrias ayudarme???

Este codigo me imprime Codigo de barras y pues el texto que yo misma suubo..plis ayudame con esto ....


Private Sub Imprimir_btn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Imprimir_btn.Click
DialogoImprimir.PrinterSettings = DialogoImprimir.PrinterSettings
DialogoImprimir.ShowDialog()
Impresora.Print()
End Sub

Sub Impresora_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
CargarFuente()
' imprimimos la cadena en el margen izquierdo
'Dim xPos As Single = e.MarginBounds.Left
' la posición superior
'Dim yPos As Single = e.MarginBounds.Top
Dim font1 As New Font("Arial", 12, FontStyle.Regular)
'Dim lineHeight As Single = font1.GetHeight(e.Graphics)
'Dim leftMargin As Single = e.MarginBounds.Left
'Dim ypos As Single = e.MarginBounds.Top

e.Graphics.DrawString(Valor_lbl.Text, font1, Brushes.Black, 30, 30)
e.Graphics.DrawString(Codigo_lbl.Text, MiFuente, Brushes.Black, 30, 30)
e.Graphics.DrawString(Label1.Text, font1, Brushes.Black, 30, 30)


End Sub
End Class

Tony Valderrama dijo...

Estimada MAría:

Me parece que tienes que jugar con las coordenadas donde estás imprimiendo para que no se amontone. También puedes jugar con la fuente y su tamaño, pero yo intentaría primero mover las coordenadas en las funciones DrawString.

Lcda. Luzmila J. Cairo Meza dijo...

Mi hermano te Felicito Tremendo trabaj, gracias por la Informacion.

Jose Luis Ramirez

Favio dijo...

Saludos, por favor necesito utilizar en vb2010 el metodo print como lo hacia en vb6.0, es decir para imprimir texto en el formulario sin ningun otro objeto..

Gracias por tu ayuda.

Tony Valderrama dijo...

La primera cosa que se me ocurre es usar el GDI para usar la función DrawString. Es más rollo, pero es posible. Si quieres ejemplos del uso del GDI para dibujar en la ventana, puedes ver estos posts:

http://tony-valderrama.blogspot.mx/2010/11/dibujando-dibujando-en-vb-net.html

http://tony-valderrama.blogspot.com/2006/11/lneas-y-cuadrados-ejemplo-del-uso-de.html

Tal vez haya una forma más sencilla, pero no sé cuál es.

¡Saludos!

Carlos Luis dijo...

Que tal Tony! de verdad tremendo tutorial, te felicito, mas facil imposible seguir esos pasos, pero tengo una duda; cuando dices en el botón de configurar impresora es solamente para la cantidad de copias y no puedes cambiar de impresora? porque lo estoy intentando y no cambia de impresora! Saludos!

Carlos Luis dijo...

Y ya lo resolví, agregando esta linea de código: PrintDialog1.PrinterSettings = PrintDocument1.PrinterSettings
(no se si ha alguien mas le sucedería lo mismo, pero allí esta la respuesta en caso de que no les funcione, a mi me funciono agregándole esto). Saludos!

Tony Valderrama dijo...

Mil gracias por la observación y compartir la solución, Carlos Luis.

Anónimo dijo...

Olaaaaaa oie como ago para imprimir lo q esta dentro de un grid me urge gracias!!1

wingflare dijo...

Buenisimo compadre, que suerte haberme topado con tu blog, muy bueno!

Anónimo dijo...

felicidades bro que buen tuto

Anónimo dijo...

Para imprimir con un sólo botón considerando:
1. Escoger impresora
2. Escoger tipo de documento
3. Vista Preliminar

'Seleccion de impresora
PrintDialog1.ShowDialog()
PrintDocument1.PrinterSettings = PrintDialog1.PrinterSettings
PrintDocument1.PrinterSettings.Copies = 1

'Configuracion de Pagina
PageSetupDialog1.PageSettings = PrintDocument1.DefaultPageSettings
PageSetupDialog1.ShowDialog()
PrintDocument1.DefaultPageSettings = PageSetupDialog1.PageSettings

'Vista Preliminar
PrintPreviewDialog1.Document = PrintDocument1
PrintPreviewDialog1.ShowDialog()

Tony Valderrama dijo...

¡Gracias por la aportación!

Unknown dijo...

Hola amigo, que buen tuto haz hecho, es el primero que encuentro con ese nivel de claridad y simpleza.
Ahora me gustaría hacerte una consulta. Yo tengo un richtextbox y en el escribo varias cadenas con distintos tamaños de fuente, alineaciones, formatos e incluso unas imagenes. Ahora me gustaria poder pasar ese richtextbox a un printdocument con el mismo formato sin tener k redibujarlo completamente dato por dato. será esto posible? o tengo que obligadamente dibujar todo denuevo?

Tony Valderrama dijo...

Estimado Jorge:

Me da gusto que te haya servido el tutorial.

De lo que preguntas, ha de haber manera, pero la desconozco. Yo buscaría algo relacionado a impresión de archivos RTF... a fin de cuentas el RichTextBox tiene los mismos datos...

Si encuentras la solución, av,isame.

¡Saludos!

Ivan Sanchez dijo...

Disculpa me podrias pasar el proyecto, mi correo es ing.ivansanchez@gmail.com, lo que pasa que estoy relizando una aplicacion para imprimir un formato, y me interasa la parte donde tu imprimes un formato que ralizte y lo guardaste en PNG.

Anónimo dijo...

HOLA PUEDES AYUDARME CON LA IMPRESION EN VARIAS PAGINAS???
COMO LO HAGO GRACIAS
BUEN POST

Unknown dijo...

K onda Amigo oye me podrias pasar tu proyecto es para guiarme es que estoy haciendo un proyecto y nadasmas me falta eso gracias por tu atencion si me lo quieres enviar mi correo es palafox.santiago@gmail.com
gracias de antemano

Anónimo dijo...

hola!! me sirvio de muchoo esta pagina!! pero me qeda una dudaa en la vista previaa, como hago para cambiar de renglon, porqe al momento de seleccionar la vista, me junta todo los datos en una sola lineaa... gracias!

Tony Valderrama dijo...

Para cambiar de renglón, cambia las coordenadas en la función DrawString.

Anónimo dijo...

hola tony :D mi pregunta es que estoy realizando un programita que guarde la informacion en un blog de notas y con otro boton mandar a imprimir la informacion guardada y no c como hacerle :/ si m pudieses ayudar t lo agradecira de corazon saludos :)

Tony Valderrama dijo...

Estimado Anónimo:

Lo más fácil sería leer el archivo de texto (el que guardas en el bloc de notas) línea por línea (con las instrucción ReadLine) y en cada línea escribirlo a la hoja con un DrawString. Solo tienes que tener una variable que controle la variable Y (para ir cambiando la distancia entre renglones).

Si tienes dudas sobre cómo leer de un archivo, fíjate en este post:
http://tony-valderrama.blogspot.mx/2006/12/generando-archivos-secuenciales-con.html

¡Saludos!

Anónimo dijo...

Buen dia Tony excelente informacion, en lo personal estoy iniciando con esto de la impresion con vb 2010, y estoy realizando un proyecto para mi trabajo, quisiera pedirte de ser posible tu proyecto o bien la forma donde tienes el codigo de impresion funcionando, te lo agradeceria eternamente mi correo es cosverboj@outlook.com

Anónimo dijo...

Tremendo manual ..gracias por la ayuda.. saludos

Anónimo dijo...

Oye una pregunta todo muy bien... pero como haces para que los botones no sean esquinados sino redondeados

Tony Valderrama dijo...

No hay forma de hacer botones redondeados con el objeto Button.

Lo que puedes hacer es crear una imagen con los botones como tu los quieras (redondeados o como sea) y ponerlo en un control PictureBox o Image (se me olvida el nombre) y asignarle código cuando hagan clic sobre él. También puedes asignar código para que la imagen cambie cuando el mouse pase por encima o cuando es presionado. Es un poco más de trabajo, pero puedes tener botones de la forma en que se te antojen.

¡Saludos!

Anónimo dijo...

excelente ejercicio

El Tony y sus ondas...

Related Posts Plugin for WordPress, Blogger...