La impresión de documentos continúa suponiendo una parte realmente importante en las aplicaciones de caracter empresarial. En el siguiente artículo encontrarás las principales pautas a tener en cuenta a la hora de implementar dicha capacidad en tus desarrollos multiplataforma con Xojo. Esta es una traducción al castellano de la entrada disponible en la web de desarrolladores de Xojo.
En el caso de las aplicaciones de escritorio, la impresión es muy similar al dibujado en la pantalla. En vez de dibujar en el objeto Graphics de un control Canvas el dibujado se produce sobre un objeto especialmente creado para la impresión. En dicho objeto se proporcionan los métodos necesarios para crear nuevas páginas y obtener también los ajustes de impresión.
Cuando se trata de aplicaciones Web, la impresión es más limitada. Por lo general lo que mejor funciona es crear sencillamente el HTML, mostrarlo en un control HTML Viewer e imprimirlo.
Impresión de escritorio
Ajustes de impresión
Antes de que podamos imprimir algo hemos suele presentarse al usuario la opción de seleccionar la impresora a usar. Esto es lo que se puede hacer utilizando la clase PrinterSetup, encargada de mostrar el cuadro de diálogo correspondiente a Ajustar Página para el sistema operativo en cuestión. Además, esta clase devuelve los ajustes establecidos, de modo que puedas utilizarlos posteriormente de nuevo sin que debas de volver a consultar al usuario.
' mPrinterSettings es una propiedad String de la ventana Dim ps As New PrinterSetup ps.SetupString = mPrinterSettings If ps.PageSetupDialog Then mPrinterSettings = ps.SetupString End If
Dado que mPrinterSettings
es una String, puedes guardarla fuera de la app (como por ejemplo en una base de datos o en un archivo), de modo que puedas emplearla la próxima vez que imprima el usuario.
La clase PrinterSetup tiene, entre otras, propiedades para los ajustes de impresión como la orientación, tamaño de página y resolución. Lo que has de tener en cuenta es que PrinterSetup no está soportado en las aplicaciones de Linux.
Imprimir Texto y Gráficos
Para imprimir texto y gráficos sólo has de dibujar sobre el objeto Graphics de la impresora. Para obtener dicho objeto puedes llamar a los métodos globales OpenPrinterDialog u OpenPrinter. La única diferencia entre estos dos métodos es que uno muestra el diálogo de Impresión y el otro no. Dado que el sistema de impresión en macOS tiene la capacidad de imprimir a PDF, puedes emplear este método para generar archivos PDF con facilidad. En Windows puedes instalar un controlador de impresión “Imprimir a PDF” que permita generar archivos PDF a partir de la impresión.
Puesto que estás dibujando en un objeto Graphics, puedes utilizar todos los comandos que ya estás habituado a utilizar en un objeto gráfico normal. Además, también puedes utilizar el método NextPage específico de impresión para crear múltiples páginas. El siguiente ejemplo imprime “Hola” en la página 1 y “Mundo” en la página 2:
Dim ps As New PrinterSetup If ps.PageSetupDialog Then Dim page As Graphics page = OpenPrinterDialog(ps) If page <> Nil Then ' Dibuja el texto en la página 1 con 2,54 cm de márgen superio/izquierdo page.DrawString("Hola", ps.HorizontalResolution, ps.VerticalResolution) page.NextPage ' Dibuja texto en la página 2 con 2,54 cm sobre el marge superior/izquierdo page.DrawString("Mundo", ps.HorizontalResolution, ps.VerticalResolution) End If End If
También puedes utilizar cualquier ajuste de impresora que se haya almacenado previamente utilizando la clase PrinterSetup.
Dim ps As New PrinterSetup ps.SetupString = mPrinterSettings ' Propiedad que contiene ajustes guardados previamente If ps.PageSetupDialog Then mPrinterSettings = ps.SetupString ' Obtener nuevos ajustes Dim page As Graphics ' Usar ajustes de Impresión page = OpenPrinterDialog(ps) If page <> Nil Then ' Dibuja texto en la página 1 con 2,54 cm sobre el margen superior/izquierdo page.DrawString("Hola", ps.HorizontalResolution, ps.VerticalResolution) page.NextPage ' Dibuja texto en la página 2 con 2,54 cm sobre el margen superior/izquierdo page.DrawString("Mundo", ps.HorizontalResolution, ps.VerticalResolution) End If End If
Cada vez que llamas al método NextPage se envía la página actual a la impresora y se borra el objeto gráfico (en este caso la página) de modo que puedas comenzar a dibujar el nuevo contenido. La página final se envía a la impresora cuando la página sale del ámbito.
Para imprimir sin mostrar el diálogo de Impresión, sólo has de invocar el método OpenPrinter:
Dim ps As New PrinterSetup Dim page As Graphics page = OpenPrinter(ps) If page <> Nil Then ' Dibuja texto en la página 1 con 2,54 cm sobre el margen superior/izquierdo page.DrawString("Hola", ps.HorizontalResolution, ps.VerticalResolution) page.NextPage ' Dibuja texto en la página 2 con 2,54 cm sobre el margen superior/izquierdo page.DrawString("Mundo", ps.HorizontalResolution, ps.VerticalResolution) page.NextPage End If
Imprimir múltiples páginas de texto
Para imprimir múltiples páginas, has de parsear cada línea e imprimirla si cabe en la página. Si no cabe, entonces llamas a NextPage de modo que el texto comenzará a imprimirse en la parte superior de la siguiente página.
Una aproximación habitual consiste en dividir el texto en párrafos, llevando la cuenta de la altura de la página y la altura del siguiente párrafo de texto a imprimir para estar seguro de que cabrá en la página. Si no es así, entonces se envía la página actual a la impresora y se crea una nueva página para comenzar la impresión del siguiente párrafo.
Este código muestra como imprimir texto de una TextArea en múltiples páginas:
Dim ps As New PrinterSetup If ps.PageSetupDialog Then Dim page As Graphics page = OpenPrinterDialog(ps) If page <> Nil Then ' Dibuja texto en la página 1 con 2,54 cm sobre el margen superior/izquierdo Dim leftMargin As Double = ps.HorizontalResolution Dim topMargin As Double = ps.VerticalResolution page.TextSize = Val(FontPopup.Text) ' Para imprimir múltiples páginas, has de parsear cada línea e imprimirla ' sólo si cabe en la página. Si no es así, entonces ' llamas a NextPage de modo que comiences a imprimir en la parte superior ' de la siguiente página. ' En primer lugar, divide el texto en múltiples párrafos Dim paragraphs() As String = ReplaceLineEndings(TextArea1.Text, EndOfLine).Split(EndOfLine) Dim pageTextHeight As Double = topMargin Dim newpageTextHeight As Double Dim lineWidth As Double For i As Integer = 0 To paragraphs.Ubound newpageTextHeight = pageTextHeight + page.StringHeight(paragraphs(i), ps.Width - leftMargin 2) If newPageTextHeight > ps.Height - topMargin 2 Then ' La cadena no cabe en la página, así que nos movemos a la página siguiente page.NextPage pageTextHeight = topMargin newpageTextHeight = pageTextHeight + page.StringHeight(paragraphs(i), ps.Width - leftMargin * 2) End If ' Si la cadena cabe en la página, dibújala page.DrawString(paragraphs(i), leftMargin, pageTextHeight, ps.Width - leftMargin * 2) ' Mantén un contador acumulado con la altura de la página a medida que se añaden nuevas cadenas pageTextHeight = newpageTextHeight ' ajusta la altura de texto de la página pageTextHeight = pageTextHeight + topMargin / 8 ' 1/8 de pulgada entre párrafos Next End If End If
El código anterior te proporciona una buena cantidad de control, pero aun queda trabajo por hacer para controlarlo todo por ti mismo. En la siguiente sección verás como puedes sacar provecho de StyledTextPrinter para hacerlo más sencillo. Además, utilizando un informe (Report).
Dado que las TextArea pueden mostrar texto con estilo y múltiples tamaños de fuente, probablemente quieras retener el texto con estilo a la hora de imprimir. la clase StyledTextPrinter se utiliza con este propósito, usando para ello el método DrawBlock.
La clase StuledTextPrinter sólo funciona con apps macOS.
Para imprimir texto con estilo has de crear en primer lugar un objeto StyledTextPrinter y llamar a continuación el método StyledTextPrinter del objeto TextArea (indicando el objeto gráfico a usar y el ancho del texto), para obtener una instancia de una StyledTextPrinter que pueda utilizarse en la impresión.
Con esta instancia puedes llamar al método DrawBlock para dibujar el texto con estilo en la página (indicando las coordenadas de inicio y la altura).
Este ejemplo imprime texto con estilo en una TextArea:
Dim stp As StyledTextPrinter Dim g As Graphics Dim p As New PrinterSetup If p.PageSetupDialog Then g = OpenPrinterDialog(p) If g <> Nil Then ' Ajusta el ancho a 7,5 pulgadas stp = PrintTextArea.StyledTextPrinter(g, 7.5 * p.HorizontalResolution) Do Until stp.EOF ' Rellena la página con texto ' y una altura de 10 pulgadas stp.DrawBlock(0, 0, 10 * p.VerticalResolution) If Not stp.EOF Then ' Hay más texto, de modo que añadimos una página g.NextPage End If Loop End If End If
Para soportar la impresión con estilo, la TextArea debe de tener activadas sus propiedades MultiLine y Styled.
Si el texto a imprimir es mayor que lo que cabe en el bloque indicado, entonces puedes iterar por el texto hasta que se imprima todo. Puedes hacer esto comprobando la propiedad EOF de la clase StyledTextPrinter tras cada llamada a DrawBlock.
Este ejemplo imprime los contenidos de una TextArea en dos columnas con un cuarto de pulgada de espacio entre las columnas:
Dim g As Graphics Dim p As New PrinterSetup If p.PageSetupDialog Then g = OpenPrinterDialog(p) ' 1 pulgada de margen Dim leftRightMargin As Double = 1 p.HorizontalResolution Dim topBottomMargin As Double = 1 p.VerticalResolution ' Ancho de página tras tener en cuenta los márgenes Dim pageWidth As Double = p.Width - (leftRightMargin * 2) ' El espacio entre columnas es de 1/4 de pulgada Dim columnGap As Double = leftRightMargin / 4 ' Calcula el ancho de columna ' Resta el espacio entre columnas para la página ' Y divide el resultado entre dos Dim columnWidth As Double = (pageWidth - columnGap) / 2 ' Tamaño de la página tras contemplar los márgenes Dim pageHeight As Double = p.Height - (topBottomMargin 2) Dim stp As StyledTextPrinter stp = PrintTextArea.StyledTextPrinter(g, pageWidth) stp.Width = columnWidth Dim columnToPrint As Integer = 1 Do Until stp.EOF stp.DrawBlock(leftRightMargin + (columnWidth + columnGap) (columnToPrint - 1), _ topBottomMargin, pageHeight) If columnToPrint = 2 Then ' printing last column If Not stp.EOF Then ' more text to print g.NextPage columnToPrint = 1 End If Else ' more columns to print on this page columnToPrint = columnToPrint + 1 End If Loop End If
Impresión HTML
Otra técnica que puedes usar es la de crear lo que desees imprimir en HTML, mostrarlo en un HTMLViewer y llamar luego a su método Print. Esto puede resultar de utilidad en algunos casos para la impresión de informes sencillos. Por ejemplo, este código carga un HTMLViewe con algo de HTML:
Dim html As String = "Hello, World!"
HTMLViewer1.LoadPage(html, GetTemporaryFolderItem)
Este código mostrará a continuación el cuadro de diálogo de impresión para imprimir el HTML:
HTMLViewer1.Print(True)
Como puedes observar resulta realmente sencillo, y en combinación con la aplicación de CSS puede resultar incluso más beneficioso. Por ejemplo, podrías utilizar la clase MarkdownParser para Xojo para generar el HTML con los estilos CSS deseados a partir de un conjunto de texto escrito en Markdown e imprimir el resultado tal y como se ha indicado.
todo eso esta bien pero si cambio xojo2018r1 la calidad se pìerde
porque el GDI vs directd2 no se entienden lo compilo para 32 bits
y mis impresiones salen mal sin embargo cuando compilo con xojo2013 no tengo problemas
espero tu comentario
gracias
Hola,
Sin ver el código fuente… es imposible saber por qué sale mal en 2018r1. ¿Igual tiene que ver con la relación entre HDPI y la impresión? Lo dicho, necesito más pistas 😉
Javier