André Alves de Lima

Talking about Software Development and more…

Imprimindo informações direto na impressora com C#

Alguns anos atrás eu escrevi um artigo sobre impressão direto na impressora com C#. Esse artigo acabou ficando bastante popular aqui no site, por isso resolvi gravar uma versão em vídeo desse artigo. Aqui vai o resultado:

Listando as impressoras instaladas

A lista de impressoras instaladas no sistema operacional está disponível no .NET a partir da propriedade “InstalledPrinters” da classe “PrinterSettings“, que fica localizada dentro do namespace “System.Drawing.Printing“:

        // C#
        public Form1()
        {
            InitializeComponent();

            CarregarImpressoras();
        }

        private void CarregarImpressoras()
        {
            impressoraComboBox.Items.Clear();

            foreach (var impressora in System.Drawing.Printing.PrinterSettings.InstalledPrinters)
            {
                impressoraComboBox.Items.Add(impressora);
            }
        }
    ' VB.NET
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        CarregarImpressoras()
    End Sub

    Private Sub CarregarImpressoras()
        ImpressoraComboBox.Items.Clear()

        For Each Impressora In System.Drawing.Printing.PrinterSettings.InstalledPrinters
            ImpressoraComboBox.Items.Add(Impressora)
        Next
    End Sub

Imprimindo texto em uma página

Para imprimirmos informações direto na impressora no .NET, temos que utilizar a classe “PrintDocument“. Uma vez criada uma instância dessa classe, temos que implementar o código do evento “PrintPage” e chamar o método “Print” para iniciar a impressão. O evento “PrintPage” será chamado uma vez para cada página a ser impressa:

        // C#
        private void imprimirButton_Click(object sender, EventArgs e)
        {
            using (var pd = new System.Drawing.Printing.PrintDocument())
            {
                pd.PrinterSettings.PrinterName = impressoraComboBox.SelectedItem.ToString();
                pd.PrintPage += Pd_PrintPage;
                pd.Print();
            }
        }

        private void Pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {

        }
    ' VB.NET
    Private Sub ImprimirButton_Click(sender As Object, e As EventArgs) Handles ImprimirButton.Click
        Using Pd = New System.Drawing.Printing.PrintDocument()
            Pd.PrinterSettings.PrinterName = ImpressoraComboBox.SelectedItem.ToString()
            AddHandler Pd.PrintPage, AddressOf Pd_PrintPage
            Pd.Print()
        End Using
    End Sub

    Private Sub Pd_PrintPage(sender As Object, e As System.Drawing.Printing.PrintPageEventArgs)

    End Sub

Dentro do evento “PrintPage“, nós temos à nossa disposição a área gráfica da página (que fica acessível através do parâmetro do evento “e.Graphics“). Com esse objeto do tipo “Graphics“, nós conseguimos desenhar figuras geométricas, imagens e texto, utilizando os métodos “Draw*“:

O método para desenharmos texto na página é o “DrawString“. Além do texto, nós precisamos passar como parâmetro desse método a fonte, cor e área onde o texto deverá ser impresso na página. Nesse exemplo, vamos criar uma instância da fonte “Times New Roman” tamanho 14 e um “SolidBrush” de cor preta. O texto deverá ser impresso na área total da página, desconsiderando as margens (essa informação está disponível através dos parâmetros do evento – “e.MarginBounds“):

        // C#
        private void Pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {
            using (var font = new Font("Times New Roman", 14))
            using (var brush = new SolidBrush(Color.Black))
            {
                e.Graphics.DrawString(impressaoTextBox.Text, font, brush, e.MarginBounds);
            }
        }
    ' VB.NET
    Private Sub Pd_PrintPage(sender As Object, e As System.Drawing.Printing.PrintPageEventArgs)
        Using Font = New Font("Times New Roman", 14)
            Using Brush = New SolidBrush(Color.Black)
                e.Graphics.DrawString(ImpressaoTextBox.Text, Font, Brush, e.MarginBounds)
            End Using
        End Using
    End Sub

Imprimindo texto em múltiplas páginas

A implementação apresentada acima funciona muito bem desde que o texto caiba em uma única página. Caso o texto seja maior, aí temos que fazer alguns ajustes. Primeiramente, temos que calcular a quantidade de texto que poderá ser impressa em cada página. Isso pode ser feito através do método “MeasureString” da classe “Graphics“. Esse método retornará a quantidade de caracteres que cabem em uma determinada área da página.

Além disso, teremos que criar uma variável no nível do formulário para controlarmos o texto que ainda está faltando para ser impresso. Essa variável será inicializada antes da impressão com o texto completo e será reduzida a cada página que for sendo impressa.

Por fim, nós precisamos informar de alguma maneira para o PrintDocument que existem mais páginas para serem impressas. Isso é feito através da propriedade “e.HasMorePages“, que deve ser configurada como “true” caso ainda exista texto para ser impresso. Quando essa propriedade é configurada como “true“, o evento “PrintPage” será disparado novamente e o restante do texto será impresso na próxima página.

Veja só como fica o código completo com suporte a múltiplas páginas:

        // C#
        private void imprimirButton_Click(object sender, EventArgs e)
        {
            using (var pd = new System.Drawing.Printing.PrintDocument())
            {
                pd.PrinterSettings.PrinterName = impressoraComboBox.SelectedItem.ToString();
                pd.PrintPage += Pd_PrintPage;
                _texto = impressaoTextBox.Text;
                pd.Print();
            }
        }

        private string _texto;
        private void Pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {
            using (var font = new Font("Times New Roman", 14))
            using (var brush = new SolidBrush(Color.Black))
            {
                int caracteres = 0;
                int linhas = 0;

                e.Graphics.MeasureString(_texto, font, new Size(e.MarginBounds.Width, e.MarginBounds.Height - font.Height + 1), StringFormat.GenericTypographic, out caracteres, out linhas);

                e.Graphics.DrawString(_texto.Substring(0, caracteres), font, brush, e.MarginBounds);

                _texto = _texto.Substring(caracteres);

                e.HasMorePages = !string.IsNullOrWhiteSpace(_texto);
            }
        }
    ' VB.NET
    Private Sub ImprimirButton_Click(sender As Object, e As EventArgs) Handles ImprimirButton.Click
        Using Pd = New System.Drawing.Printing.PrintDocument()
            Pd.PrinterSettings.PrinterName = ImpressoraComboBox.SelectedItem.ToString()
            AddHandler Pd.PrintPage, AddressOf Pd_PrintPage
            Texto = ImpressaoTextBox.Text
            Pd.Print()
        End Using
    End Sub

    Private Texto As String
    Private Sub Pd_PrintPage(sender As Object, e As System.Drawing.Printing.PrintPageEventArgs)
        Using Font = New Font("Times New Roman", 14)
            Using Brush = New SolidBrush(Color.Black)
                Dim Caracteres As Integer = 0
                Dim Linhas As Integer = 0

                e.Graphics.MeasureString(Texto, Font, New Size(e.MarginBounds.Width, e.MarginBounds.Height - Font.Height + 1), StringFormat.GenericTypographic, Caracteres, Linhas)

                e.Graphics.DrawString(Texto.Substring(0, Caracteres), Font, Brush, e.MarginBounds)

                Texto = Texto.Substring(Caracteres)

                e.HasMorePages = Not String.IsNullOrWhiteSpace(Texto)
            End Using
        End Using
    End Sub

Baixe o projeto de exemplo

Para baixar o projeto de exemplo desse artigo, assine a minha newsletter. Ao fazer isso, além de ter acesso ao projeto, você receberá um e-mail toda semana sobre o artigo publicado e ficará sabendo também em primeira mão sobre o artigo da próxima semana, além de receber dicas “bônus” que eu só compartilho por e-mail. Inscreva-se utilizando o formulário no final do artigo.

Concluindo

Imprimir informações direto na impressora com C# e VB.NET não é uma tarefa muito difícil. Através da classe “PrintDocument” nós conseguimos imprimir figuras geométricas, imagens e texto diretamente na impressora, sem necessitar de uma janela de “preview“. No vídeo de hoje você aprendeu a listar as impressoras instaladas no sistema operacional e a utilizar a classe “PrintDocument” para imprimirmos texto em uma única página e em múltiplas páginas.

E você, já precisou imprimir informações direto na impressora? Utilizou a classe “PrintDocument“? Como é que foi a sua experiência? Conte-nos mais detalhes na caixa de comentários abaixo!

Até a próxima!

André Lima

Photo by Peter Shanks used under Creative Commons
https://pixabay.com/en/startup-start-up-notebooks-creative-593327/

Song Rocket Power Kevin MacLeod (incompetech.com)
Licensed under Creative Commons: By Attribution 3.0 License
http://creativecommons.org/licenses/by/3.0/

Newsletter do André Lima

* indicates required



Powered by MailChimp

6 thoughts on “Imprimindo informações direto na impressora com C#

  • Ahmed Kelany disse:

    That’s great!
    Previously in order to print a receipt in my application I used to make an RDLC report and print it directly by rendering to an Image!
    Of coarse it wasn’t very good for performance and I face another issue when printing from computers with different screen resolutions, the receipt gets cropped or too small :(

    I used PrintDocument for printing barcodes and had some issues adjusting the text since it often had Arabic text, one draw back was I always used PrintDocument as a component in a form, so I had relatively a lot of duplicate code, since I used a PrintDocument for each form where I need to print barcodes.

    Seeing here that it can be used independently from a form is a great help, now I can extract all the logic to a helper class and used it instead of the duplicate code!

    Thanks very much.

    • andrealveslima disse:

      Hi Ahmed!

      Yes, it is possible to instantiate a PrintDocument independently of the Form.. This way, as you said, you could easily join all your logic in a helper class, instead of duplicating it in every Form you need..

      I’m glad I could help.. Let me know if you face difficulties adjusting your code..

      Regards,
      André Lima

  • André Rogério Bononi disse:

    Olá, André.

    Cara, parabéns novamente! Mais um excelente post!
    Agora, uma pergunta: com este método é possível fazer impressões com quadros? Digo, conseguir formatar uma impressão como se fosse um relatório montado no Report Viewer ou no Crystal Reports?

    Abraços!

    • andrealveslima disse:

      Olá André, muito obrigado pelo comentário!

      Desculpe, mas não entendi direito a sua dúvida.. O que seria impressões com quadros? O PrintDocument é extremamente flexível, você pode imprimir qualquer informação em qualquer lugar da página.. Porém, por causa de toda essa flexibilidade, ele às vezes acaba sendo difícil de utilizar porque você tem que posicionar tudo “na mão”..

      Abraço!
      André Lima

  • deuzivaldo disse:

    Bom professor mais eu não consigo ver como baixar seus projetos

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *