1.0 Introdução.

2.0 Impressão em .NET.

2.1 - Controles para Impressão em .NET.

2.2 - Conhecendo mais o NameSpace System.Drawing.Printing.

2.3 - Criando uma classe Personalizada.

3.0 Conclusão
4.0 Referências.
 
 
1.0 Introdução
 

            O Visual Studio contempla de forma integrada diversas ferramentas utilizadas para a elaboração de relatórios tais como ReportView, Cristal Report. Além desta ferramentas o .Net Visual Studio contepla outros controles que permitem a construção de novas ferramentas para impressão de relatórios.

 

 

O Framework  .NET fornece aos desenvolvedores 5 controles principais que possibilitam a impressão de documentos. Estes controles podem ser visto na figura 1.

PageSetupDialog – Este controle representa uma caixa de dialogo na qual o usuário pode definir propriedades do documento a ser impresso tais como tamanho do papel, tipo de papel, margens etc.

PrintDialog – Este controle representa uma caixa de dialogo na qual permite o usuário definir a impressora na qual quer imprimir a página, bem como outras configurações.

PrintDocument – Este representa o documento a ser impresso, tratasse do controle chave para o processo de impressão.

            PrintPreviewDialog – Este controle representa uma caixa de dialogo na qual o documento pode ser visualizado.

PrintPreviewControl – Este representa um contêiner de visualização de documentos, permitindo ao desenvolvedor personalizar a forma de visualização do documento.

Para realizar qualquer impressão é necessário entender o funcionamento do  controle PrintDocument. Este controle possui os seguintes eventos.

BeginPrint – Este evento é ativado uma única vez quando o processo de impressão inicia.

EndPrint – Este evento é ativado uma única vez quando a impressão é finalizada. Isto é, quando não existe mais documento a ser impresso.

QueryPageSettings – Este evento é disparado logo antes do evento PrintPage. Neste evento é possível fazer alterações na configuração de uma pagina particular.

PrintPage – Este evento é disparado para toda pagina a ser impressa. Na assinatura deste evento é passado como parâmetro um objeto da classe PrintPageEventArgs, este objeto tem uma propriedade denominada  hasmorepage. Esta propriedade recebe um valor verdadeiro ou falso na qual o se pode definir a continuidade da impressão.

O objeto da classe PrintPageEventArgs possui também uma propriedade Graphics que retorna um objecto da classe Graphics, esta propriedade permiti efetivamente que seja desenhado o conteúdo do documento a ser impresso. A classe Graphis possui metodos para desenhar linhas, texto, curvas etc. A classe  

         Vejamos um exemplo de um código utilizando estes controles. O código a seguir escreve na superfície do objeto gráfico através do metodo DrawString e logo em seguida informa que não existe mais nada a ser impresso, isto é, setando a propriedade hasmorepage como false.
 
 

private void printButton_Click(object sender, EventArgs e)

    {

       try

       {

              PrintDocument pd = new PrintDocument();

              pd.PrintPage += new PrintPageEventHandler(this.pd_PrintPage);

              pd.Print();

           } 

       } 

       catch(Exception ex)

       {

           MessageBox.Show(ex.Message);

       }

    }

private pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)

{

     e.Graphics.DrawString(“Imprindo em .NET”, new font(“Arial”,10), Brushes.Black, 0,0);

     e.HasMorePages = false;

}

 
 

A chamada ao método print desencadeia todo o processo de impressão. Ocorre inicialmente o disparo do evento BeginPrint, em seguida o evento QueryPageSettings é disparadao logo depois o evento PrintPage é disparado dando inicio a um loop de impressão cujo termino é definido pela propriedade hasmorepage(true o processo continua, false o processo termina). Quando o loop é encerrado o evento EndPrint é disparado, concluindo assim o ciclo de impressão. A figura a seguir ilustrar o a seqüência de eventos.

          Uma das dificuldades no processo de impressão consiste na manipulação e posicionamento do conteúdo a ser impresso na superficie gráfica, pois na verdade tudo é desenhado, mesmo um simples texto.

           A seguir é apresentado um exemplo onde se utiliza o controle PrintDialog. O método ShowDialog deste controle exibir uma janela. Case o usuário click no botão imprimir presente na janela do dialogo, fará com que a mesma retorne DialogResult.OK. Confirmando assim a impressão. Como se pode perceber o controle PrintDialog esta associado a classe PrintDocument  através da propriedade Document.

private void printDialog_Click(object sender, EventArgs e)

{

  try

     {

     PrintDocument pdoc = new PrintDocument();

     pdoc.PrintPage += new PrintPageEventHandler(this.pd_PrintPage);

     PrintDialog dialog = new PrintDialog();

     dialog.Document = pdoc;

     if (dialog.ShowDialog() == DialogResult.OK)

        {

         pdoc.Print();

         }

      } 

   catch(Exception ex)

      {

           MessageBox.Show(ex.Message);

      }

    }

 
 

Vejamos a seguir um código utilizando o controle PrintPreviewDialog. Este controle esta associado ao controle PrintDocument através da propriedade Document.

private void printPreview_Click(object sender, EventArgs e)

{

    PrintPreviewDialog ppd = new PrintPreviewDialog();

    PrintDocument pdoc = new PrintDocument();

    try

         {

        pdoc.PrintPage += new PrintPageEventHandler(this.pd_PrintPage);

           ppd.Document = pdoc;

           ppd.ShowDialog();

          }

   catch(Exception ex)

      {

           MessageBox.Show(ex.Message);

      }

    }

 

Vejamos agora um exemplo de código utilizando o controle PageSetupDialog. Este controle tem uma propriedade denominada PageSettings que representa das as configurações do documento. Estas configuraçoes devem ser repassadas ao controle PrintDocument atraves da propriedade DefaulPageSettings.

private void SetupPreview_Click(object sender, EventArgs e)

{

   PageSetupDialog psd = new PageSetupDialog();

   psd.Document = pdoc;

   psd.PageSettings = pdoc.DefaultPageSettings;

 

  if (psd.ShowDialog() == DialogResult.OK)

   {

      pdoc.DefaultPageSettings = psd.PageSettings;

   }

 

Como pode ser observado toda vez que um controle PrintDocument tem seu evento PagePrint disparado, uma caixa de dialog é mostrado com a seguinte mensagem “Generating pages...”. Esta caixa de dialogo tem por finalidade mostrar a quantidade de paginas que estão sendo geradas, bem como permite ao usuário cancelar o processo de geração das mesmas. Todavia este recurso pode ser contornado, permitindo que o desenvolvedor possa personalizar a mensagem exibida ou até mesmo eliminar a caixa de dialog. Entretanto para fazer isto é necessário conhecer um pouco mais as classes presentes no namespace System.Drawing.Printing.

Vejamos um exemplo da utilização do controle PrintPreviewControl. Este controle através da propriedade de sua document se associa ao controle PrintDocument. Dentre as diversas propriedades existentes neste controle pode-se se destacar as seguintes:

Rows e Cols: defini o numero de linhas e colunas que o contêiner terá para visualização dos documentos de forma simultânea. Funciona como uma matriz na qual em cada interseção linha e coluna esta contida uma página.

Zoom - Esta propriedade define o tamanho em que a pagina será vista. Os valores assumidos por esta propriedade devem ser positivos e maiores que zero, sendo que o valor 1,0 indica 100%.

StartPage – Esta propriedade defini o índice da pagina  que deve ser apresenta. As paginas geradas pelo documento são armazenadas em uma lista. Para ser acessar as paginas da lista deve-se efetua incrementos sobre esta propriedade.

private void Preview_Click(object sender, EventArgs e)

{

   PrintDocument pdoc = new PrintDocument();

   pdoc.PrintPage += new PrintPageEventHandler(this.pd_PrintPage);

    PrintPreviewControl ppvc = new System.Windows.Forms.PrintPreviewControl();

    ppvc.Document = pdoc;

    ppvc.Dock = System.Windows.Forms.DockStyle.Fill;

    this.Controls.Add(ppvc);

    ppvc.BringToFront();

 } 

 

 

Diferentemente dos outros controles o controle PrintPreviewControl não tem um método explicito que dispara o evento PrintPage. Este evento somente é ativado no momento em que o formulário for desenhar o controle PrintPreviewControl.

 

2.2 - Conhecendo mais o NameSpace System.Drawing.Printing

 

            Uma propriedade bastante interessante da classe PrintDocument é a propriedade PrintController. A classe PrintController representa os controladores de impressão no .NET. Trata-se de uma classe base abstrata. Existem 3 classes derivadas de PrintController que possuem funcionalidade implementas. Vejamos a seguir as três classes derivadas:

  • PrintControllerWithStatusDialog: Esta classe tem a responsabilidade de controlar a impressão com a apresentação uma caixa de dialogo que mostra o nome do documento e a pagina que esta sendo impressa.
  • StandardPrintController: Esta classe tem a mesma responsabilidade e funcionamento da classe PrintControllerWithStatusDialog, com a diferença de não apresenta nenhuma caixa de dialogo. Permitindo a personalização.
  • PreviewPrintController: Esta classe tem a responsabilidade de controlar a impressão através de uma saída gráfica na forma de um objeto bitmap que representa cada pagina.

 

A classe abstrata PrintController defini 4 métodos:

  • void OnStartPrint(PrintDocument prndoc, PrintEventArgs pea)
  • Graphics OnStartPage(PrintDocument prndoc, PrintPageEventArgs ppea)
  • void OnEndPage(PrintDocument prndoc, PrintPageEventArgs ppea)
  • void OnEndPrint(PrintDocument prndoc, PrintEventArgs pea)

 

     Pode se visto anteriormente que o processo de impressão inicia com a chamada ao método Print da classe PrintDocument.

     O PrintDocument através de sua propriedade PrintController chama pelos os 4 métodos de uma instancia especifica da classe PrintController

    PrintDocument chama o metodo OnStartPrint de PrintController após disparar seu próprio evento BeginPrint. PrintDocument chama OnStartPage e OnEndPage antes e após disparar cada evento PrintPage. Para finalizar PrintDocument chama OnEndPrint do PrintController após disparar seu próprio evento EndPrint..

        Em particular o método OnStartPage do objeto PrintController é responsável por obter um objeto Gráfico (Graphics) que é passado como parametro para o evento PrintPage. Este objeto Graghics determina a area grafica de saida do evento PrintPage. Esta saída gráfica geralmente é a impressora que é controlada pelo objeto PrintController.

             Um objeto da classe PreviewPrintController cria um objeto gráfico com base em um bitmap para representar a pagina impressa. O conjunto de paginas geradas pelo objeto pode ser obtido através do método GetPreviewPageInfo.

            Por padrão a propriedade PrintController de PrintDocument é um objeto do tipo PrintContro!lerWithStatusDialog.

            Observando melhor a classe PrintControllerWithStatusDialog pode-se perceber através que seus construtores que a unida coisa que é possível customizar é o titulo da caixa de dialogo. No exemplo a seguir o titulo da caixa de dialogo é alterado.

private void Preview_Click(object sender, EventArgs e)

{

    PrintDocument pdoc = new PrintDocument();

    pdoc.PrinController= new PrintControllerWithStatusDialog(new StandardPrintController(), "Imprimindo…");

} 

 

 

 

Em virtude das limitaçoes imposta pela classe PrinControllerWithDialog, deve-se derivar uma nova classe permintido assim acrescentar as caracteristicas que se achar necessario. A classe denominada CustomPrintControllerWithStatusDialog é derivada de StandardPrintController. Esta classe tem a mesma funcionalidade básica da classe  PrintControllerWithStatusDialog. As diferenças presentes nesta classe é que a mesma permite personalizar a caixa de dialogo e obter o total de paginas geradas de mateira prática.

Codigo da Classe  CustomPrintControllerWithStatusDialog

    public class CustomPrintControllerWithStatusDialog : StandardPrintController

    {

 

        FormDialog formdialgo;

        private int pageindex = 0;

 

        public CustomPrintControllerWithStatusDialog()

        {

           

        }

 

        public override void OnEndPage(PrintDocument document, PrintPageEventArgs e)

        {

            base.OnEndPage(document, e);

        }

 

        public override Graphics OnStartPage(PrintDocument document, PrintPageEventArgs e)

        {

            formdialgo.lblPagina.Text = string.Format("Pagina {0}", pageindex);

            Application.DoEvents();

            if (formdialgo.DialogResult == DialogResult.Cancel)

                e.Cancel = true;

            pageindex += 1;

            return base.OnStartPage(document, e);

        }

 

        public override void OnEndPrint(PrintDocument document, PrintEventArgs e)

        {

            formdialgo.Dispose();

            base.OnEndPrint(document, e);

        }

 

        public override void OnStartPrint(PrintDocument document, PrintEventArgs e)

        {

            pageindex = 1;

            formdialgo = new FormDialog();

            formdialgo.Show();

            base.OnStartPrint(document, e);

        }

 

       public int PageCount { get { return pageindex; } }

    }

 
       O codigo a seguir permite utilizar a nova classe. Para isto basta que seja criado uma instancia da classe e atribuida esta instancia a propriedade PrintController do objeto PrintDocument.

CustomPrintControllerWithStatusDialog controller;

 

private void Print_Click(object sender, EventArgs e)

{

 PrintDocumet pdoc = new PrintDocument();

 controller = new CustomPrintControllerWithStatusDialog();

 pdoc.PrintController = controller;

 pdoc.Print();

}

 
3.0 Conclusão
   
        Pode se perceber que existem inumeras possibilidades de criação e customização de controles a partir da infraestrutura basica fornecida pelo .NET framework. O namespace Printing tem muitas classes com conteúdo suficiente para se escrever um livro sobre o assunto.
 
4.0 Referencias
 

Mahesh Chand. Graphics Programming with GDI+. Addison Wesley;  2003

 

Iulian Serban, Dragos Brezoi, Tiberiu Radu, Adam Ward. GDI+ Custom Controls with Visual C# 2005. Packt Publishing Ltd;  2006