Un modo de generar un documento con un formato no muy complejo e imprimirlo es utilizando un formulario, añadiendole los controles deseados hasta obtener el aspecto requerido y después imprimirlo. Yo he puesto en práctica esta opción para la creación de tickets y facturas de venta.
A continuación, muestro como se realizaría esta tarea en el caso de los ticket. Para las facturas se hace de forma muy parecida, sólo hay que añadir los datos del cliente y cambiar un poco el formato.
Cuando se crea un objeto de la clase fTicket se le debe pasar una lista que incluye los artículos incluidos en la cuenta para la que se va a generar el ticket. La lista de la cuenta será una lista de objetos que contengan la información relevante de cada concepto a mostrar en el ticket.
Al mostrar el formulario se añadirán todos los controles (etiquetas, en este caso) necesariios para lograr el formato deseado. A continuación se muestra como se añadiría una línea por cada concepto en la cuenta, y posteriormente las lineas con los totales y el pie de página. La cabecera del ticket ya se ha creado en vista de diseño en el formulario ya que no cambia nunca.
Private Sub fTicket_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown
Dim itemCuenta As ItemCuenta
Dim i As Integer = 0
Dim yMax As Integer, yPie As Integer
'Para cada elemento en la lista debemos crear una línea en
'en el ticket (añadir las etiquetas correspondientes al formulario)
For Each o As Object In _listaCuenta
itemCuenta = CType(o, ItemCuenta)
'Descartamos el primer elemento porque no contiene un artículo,
'sólo la cantidad entregada por el cliente
If itemCuenta.nombreArticulo <> "Entregado" Then
Dim lblDescr As Label = New Label
lblDescr.Location = New Point(6, 134 + (i * 15))
lblDescr.Text = itemCuenta.nombreArticulo
lblDescr.AutoSize = False
lblDescr.Size = New System.Drawing.Size(117, 13)
Dim lblCantidad As Label = New Label
lblCantidad.Location = New Point(135, 134 + (i * 15))
lblCantidad.Text = itemCuenta.cantidadArticulo.ToString()
lblCantidad.AutoSize = False
lblCantidad.Size = New System.Drawing.Size(19, 13)
lblCantidad.TextAlign = System.Drawing.ContentAlignment.MiddleRight
Dim lblPVP As Label = New Label
lblPVP.Location = New Point(160, 134 + (i * 15))
lblPVP.Text = itemCuenta.precioArticulo.ToString("0.00")
lblPVP.AutoSize = False
lblPVP.Size = New System.Drawing.Size(45, 13)
lblPVP.TextAlign = System.Drawing.ContentAlignment.MiddleRight
Dim lblImporte As Label = New Label
lblImporte.Location = New Point(211, 134 + (i * 15))
lblImporte.Text = itemCuenta.importeArticulo.ToString("0.00")
lblImporte.AutoSize = False
lblImporte.Size = New System.Drawing.Size(59, 13)
lblImporte.TextAlign = System.Drawing.ContentAlignment.MiddleRight
Me.Controls.Add(lblDescr)
Me.Controls.Add(lblCantidad)
Me.Controls.Add(lblPVP)
Me.Controls.Add(lblImporte)
i += 1
End If
Next
'Obtenemos la posición de la última línea de la cuenta para desplazar
yMax = 134 + ((i - 1) * 15)
yPie = yMax + 30
'Base Imponible
Dim lblBaseImp As Label = New Label()
lblBaseImp.AutoSize = True
lblBaseImp.Location = New System.Drawing.Point(117, yPie)
lblBaseImp.Size = New System.Drawing.Size(42, 13)
lblBaseImp.Text = "BASE IMP."
Me.Controls.Add(lblBaseImp)
'Obtenemos el importe total que se corresponde con el IVA
'
Dim lblBaseImp2 As Label = New Label()
lblBaseImp2.AutoSize = False
lblBaseImp2.Location = New System.Drawing.Point(117, yPie + 17)
lblBaseImp2.Size = New System.Drawing.Size(56, 13)
lblBaseImp2.TextAlign = System.Drawing.ContentAlignment.MiddleRight
lblBaseImp2.Text = Utilidades.CalcularImporteTotalSinIVA(_listaCuenta).ToString("0.00")
'Importe IVA
Dim lblImporteIVA As Label = New Label()
lblImporteIVA.AutoSize = True
lblImporteIVA.Location = New System.Drawing.Point(195, yPie)
lblImporteIVA.Size = New System.Drawing.Size(36, 13)
lblImporteIVA.Text = "IMPORTE IVA"
Me.Controls.Add(lblImporteIVA)
'Obtenemos la suma del importe total de los artículos de la cuenta sin IVA
'
Dim lblImporteIVA2 As Label = New Label()
lblImporteIVA2.AutoSize = False
lblImporteIVA2.Location = New System.Drawing.Point(198, yPie + 17)
lblImporteIVA2.Size = New System.Drawing.Size(73, 13)
lblImporteIVA2.TextAlign = System.Drawing.ContentAlignment.MiddleRight
lblImporteIVA2.Text = Utilidades.CalcularImporteIVA(_listaCuenta).ToString("0.00")
'
Me.Controls.Add(lblBaseImp2)
Me.Controls.Add(lblImporteIVA2)
'
Dim lblTotalPagar As Label = New Label()
lblTotalPagar.AutoSize = True
lblTotalPagar.Location = New System.Drawing.Point(98, yPie + 50)
lblTotalPagar.Size = New Size(95, 13)
lblTotalPagar.Text = "TOTAL A PAGAR:"
'
Dim lblTotalPagar2 As Label = New Label()
lblTotalPagar2.AutoSize = False
lblTotalPagar2.Location = New System.Drawing.Point(201, yPie + 50)
lblTotalPagar2.TextAlign = System.Drawing.ContentAlignment.MiddleRight
lblTotalPagar2.Size = New Size(70, 13)
lblTotalPagar2.Text = Utilidades.CalcularImporteTotalCuenta(_listaCuenta).ToString("0.00")
'
Me.Controls.Add(lblTotalPagar)
Me.Controls.Add(lblTotalPagar2)
'
Dim lblEntregado As Label = New Label()
lblEntregado.AutoSize = True
lblEntregado.Location = New System.Drawing.Point(98, yPie + 72)
lblEntregado.Size = New Size(95, 13)
lblEntregado.Text = "ENTREGADO:"
'
Dim lblEntregado2 As Label = New Label()
lblEntregado2.AutoSize = False
lblEntregado2.Location = New System.Drawing.Point(201, yPie + 72)
lblEntregado2.TextAlign = System.Drawing.ContentAlignment.MiddleRight
lblEntregado2.Size = New Size(70, 13)
lblEntregado2.Text = CType(_listaCuenta(0), ItemCuenta).precioArticulo.ToString("0.00")
'
Me.Controls.Add(lblEntregado)
Me.Controls.Add(lblEntregado2)
'
Dim lblCambio As Label = New Label()
lblCambio.AutoSize = True
lblCambio.Location = New System.Drawing.Point(98, yPie + 94)
lblCambio.Text = "CAMBIO:"
'
Dim lblCambio2 As Label = New Label()
lblCambio2.AutoSize = False
lblCambio2.Location = New System.Drawing.Point(201, yPie + 94)
lblCambio2.TextAlign = System.Drawing.ContentAlignment.MiddleRight
lblCambio2.Size = New Size(70, 13)
lblCambio2.Text = (CType(_listaCuenta(0), ItemCuenta).precioArticulo - Utilidades.CalcularImporteTotalCuenta(_listaCuenta)).ToString("0.00")
'
Me.Controls.Add(lblCambio)
Me.Controls.Add(lblCambio2)
'IVA Incluido
Dim lblIVAIncluido As Label = New Label()
lblIVAIncluido.Location = New System.Drawing.Point(193, yPie + 118)
lblIVAIncluido.Text = "IVA INCLUIDO"
'
Me.Controls.Add(lblImporteIVA)
Me.Controls.Add(lblImporteIVA2)
'Gracias por su visita
Dim lblGraciasVisita As Label = New Label()
lblGraciasVisita.AutoSize = True
lblGraciasVisita.Location = New System.Drawing.Point(13, yPie + 145)
lblGraciasVisita.TextAlign = System.Drawing.ContentAlignment.MiddleRight
'lblGraciasVisita.Size = New Size(78, 13)
lblGraciasVisita.Text = "GRACIAS POR SU VISITA"
'
Me.Controls.Add(lblIVAIncluido)
Me.Controls.Add(lblGraciasVisita)
If yPie + 170 > Me.Height Then
Me.MinimumSize = New Size(Me.Width, yPie + 190)
End If
PrintDocument1.Print()
End Sub
En el código que se muestra a continuación se puede ver como se realiza la impresión del ticket. La idea consiste en dibujar el texto contenido en las etiquetas en el evento e en la misma posición en la que se situaron dichas etiquetas dentro del formulario.
Para llevar a cabo este proceso se recorren todos los controles del formulario y se descartan todos aquellos que no sean del tipo que queremos imprimir. Los que sean del tipo que deseamos imprimir se dibujarán en el objeto e en una posición acorde a la que tienen en el formulario.
Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
DibujarTicket(e.Graphics())
End Sub
Private Sub DibujarTicket(ByVal g As Graphics)
' Create the source rectangle from the BackgroundImage Bitmap Dimensions
Dim srcRect As Rectangle = New Rectangle(0, 0, Me.Width, Me.Height)
Dim nWidth As Integer = Me.Width
Dim nHeight As Integer = Me.Height
Dim destRect As Rectangle = New Rectangle(0, 0, nWidth, CInt(Math.Ceiling(nHeight / 2)))
Dim lbl As Label
Dim scalex As Double = 1 * CSng(destRect.Width / srcRect.Width)
Dim scaley As Double = 2 * CSng(destRect.Height / srcRect.Height)
Dim aPen As New Pen(Brushes.Black, 1)
' Recorre todos los controles. Determina si es un label y dibuja el valor de la propiedad text
' en la posición correcta (en función de la propiedad location del control label en cuestión)
For Each o As Object In Me.Controls
If o.GetType() = Label1.GetType() Then
lbl = CType(o, Label)
If lbl.TextAlign = ContentAlignment.MiddleRight Then
g.DrawString(lbl.Text, lbl.Font, Brushes.Black, CSng((lbl.Bounds.Right - 6 * lbl.Text.Length) * scalex),
CSng(lbl.Bounds.Top * scaley), New StringFormat())
Else
g.DrawString(lbl.Text, lbl.Font, Brushes.Black, CSng((lbl.Bounds.Left) * scalex),
CSng(lbl.Bounds.Top * scaley), New StringFormat())
End If
End If
Next
Me.Close()
End Sub