Como Imprimir utilizando TPrinter - para quem tem problemas!

23/11/2005

0

Um problema que tenho visto com grande freqüência no fórum, são pessoas com problemas de impressão utilizando o TPrinter, a maioria dos programadores utiliza geradores de impressão pela facilidade de utilizá-los, ou até mesmo pelo fato de não saberem utilizar a impressão direta, quer por TPrinter ou utilizando o WriteLn. O TPrinter possui a vantagem de poder utilizar qualquer tipo e tamanho de fonte existente no Windows, enquanto que no WriteLn utiliza-se as fontes existentes na impressora, que além de limitadas variam de impressora para impressora
Vamos a um exemplo completo com explicações de cada passo e o porquê de cada ato.
O programa baseia-se em um form contendo um botão para a impressão de dados, os quais poderão ser tirados de uma tabela, uma tabela com filtro ou através de SQL, o que não faz a menor diferença, se quiser colocar um DBGrid para a visualização dos dados, nada impede.
Vamos supor a impressão de um relatório parcial de vendas durante um determinado período, a parte da seleção do período não será mostrada.

Coloque Printers no uses do Form
Procedure TForm1.Button1Click(Sender : TObject);
Var
Linha, Coluna, Quantidade : Integer;
IndiceHorizontal, IndiceVertical, Total, TotalGeral : Real;
Código : String;
Begin
Button1.Enabled := False; // isto é para evitar que o usuário ache que a impressão está demorando e acione o botão diversas vezes provocando diversas impressões
Cursor := crHourGlass // coloca a ampulheta para informar ao usuário que o computador está efetuando um trabalho
IndiceHorizontal := Printer.PageWidth / 960;
IndiceVertical := Printer.PageHeight / 1584;
Estes dois índices horizontal e vertical são utilizados para ajustar a impressão em qualquer impressora, quer seja matricial ou jato de tinta em qualquer resolução, os números 960 e 1584 foram tirados da minha matricial com uma resolução de 120 x 144 pixels e usando papel A4. Pegue a sua impressora, escolha um tamanho de papel e uma resolução qualquer e dê um showmessage(inttostr(printer.pagewidth) + ‘ ‘ + inttostr(printer.pageheight)) para achar estes números. Na sua configuração inicial as duas divisões terão como resultado o número um, porém se modificar a resolução da impressora, ou o tamanho do papel verá que estes números mudarão, estes números serão utilizados logo abaixo.
Printer.Font.Name := ‘Arial’; // utilizo a fonte arial por ser uma fonte que normalmente está em todos os computadores
Printer.Orientation := poPortrait; // aqui certifica-se que o papel será impresso na forma retrato, pois poderia estar configurado para Printer.Orientation := poLandScape que é o modo paisagem, caso mude para o modo paisagem o printer.pagewidth e printer.pageheight devem ter os seus valores invertidos
Printer.BeginDoc; // inicia o serviço de impressão
Linha := 0;
Quantidade := 0;
TotalGeral := 0; // zera as variáveis;
With Table1 do // pega os dados de uma tabela, mas poderia ser uma Query
Begin
First; // é para confirmar que a tabela está no primeiro registro desejado, esta tabela poderá estar filtrada, caso exista uma DBGrid o usuário poderá ter selecionado algo e não estar no primeiro registro
While not eof do // para imprimir toda a tabela
Begin
With Printer.Canvas do // para evitar a digitação de printer.canvas em cada comando de impressão, o canvas é o responsável pelo processo de “desenho” no windows
Begin
If Linha = 0 then // verifica se é início de página para colocar um cabeçalho
Begin;
Font.Size := 10; // tamanho da fonte para o cabeçalho
Coluna := Round(150 * IndiceHorizontal); // aqui, é efetuada a correção para a resolução horizontal da impressora onde 150 é a posição na coluna onde estou querendo imprimir, nos arredondamentos efetuados o erro máximo será de um pixel, o que não será notado pelo usuário
TextOut(Coluna, Linha, ‘NOME DA EMPRESA’); // a coluna e a linha TEM que ser número inteiro, o texto entre aspas poderá ser uma variável tipo string
Coluna := Round(720 * IndiceHorizontal);
TextOut(Coluna, Linha, DateToStr(Now)); // impressão da data
Linha := Linha + Round(23 * IndiceVertical); aqui pega o valor da linha, faz o acréscimo e a correção da resolução vertical da impressora
Coluna := Round(250 * IndiceHorizontal);
TextOut(Coluna, Linha, ‘Venda entre: ‘ + MaskEdit1.Text + ‘ e ‘ + MaskEdit2.Text)); // imprime a informação do período
Linha := Linha + Round(28 * IndiceVertical);
Font.Size := 9;
Coluna := 0;
TextOut(Coluna, Linha, ‘CÓDIGO’); // este e os seguintes são os nomes das colunas a serem impressas
Coluna := Round(90 * IndiceHorizontal);
TextOut := Round(Coluna, Linha, ‘QUANT’);
Coluna := Round(170 * IndiceHorizontal);
TextOut(Coluna, Linha, ‘VALOR’); // acrescente quantas colunas a mais precisar utilizando o mesmo princípio
Linha := Linha + (Round(25 * IndiceVertical);
End;
Coluna := 0;
Código := IntToStr(FieldByName(‘CODIGOPRODUTO’).AsInteger); // transforma o código de inteiro para string para a impressão, para mostrar a utilização de variável e utilizando o tipo de campo;
TextOut(Coluna, Linha, Código); // imprime o código do produto
Coluna := Round(90 * IndiceHorizontal);
TextOut(Coluna, Linha, IntToStr(FieldByName(´QUANTIDADEVENDIDA’).Value)); // imprime sem utilização de variável e utilizando VALUE em vez do tipo do campo
Total := FieldByName(‘TOTAL’).AsFloat; // joga o valor do total em uma variável;
TotalGeral := TotalGeral + Total; // soma o total geral para impressão no final
Quantidade := Quantidade + 1; // soma a quantidade de produtos vendidos para a impressão no final
Coluna := Round(170 * IndiceHorizontal);
TextOut(Coluna, Linha, FloatToStrF(Total, ffFixed, 10, 2)); // pega o valor e formata o mesmo para um valor fixo com duas casas decimais. O ffFixed também pode ser ffGeneral, ffExponent, ffNumber ou ffCurrency, veja o help do Delphi
Linha := Linha + Round(20 * IndiceVertical);
If Linha >= 1440 then // verifica se já chegou no local onde quero terminar a impressão da página
Begin
Linha := 0; // zera o valor da linha para a impressão do cabeçalho na outra página, se quiser fazer controle de impressão de número de página também pode colocar aqui para que o mesmo seja impresso no final da página
Printer.NewPage; // ejeta a página
Se quiser pode acrescentar um contador de páginas aqui e imprimir o número da página
End;
End;
End;
Next; // vai para o próximo registro da tabela
End;
Printer.Canvas.Font.Size := 10; // troca o tamanho da fonte
Linha := Linha + Round(25 * IndiceVertical);
If Linha > 1400 then // verifica a posição no papel para ter certeza que a impressão ficará inteira na mesma página
Printer.NewPage;
Coluna := 0;
Printer.Canvas.TextOut(Coluna, Linha, ‘QUANTIDADE TOTAL DE ÍTENS: ’ + IntToStr(Quantidade)); // aqui também poderia ser a quantidade total de produtos vendidos, é só uma questão de escolha do que vai ser impresso
Linha := Linha + Round(25 * IndiceVertical);
Printer.Canvas.TextOut(Coluna, Linha, ‘VALOR TOTAL: ‘ + FloatToStrF(TotalGeral, ffCurrency, 10, 2); // aqui em vez de ffFixed utilizei ffCurrency para que na impressão apareça o R$
Printer.EndDoc; // com este comando acaba a impressão ejetando a página, caso não seja colocado a ejeção acontecerá porém o documento demorará mais tempo para ser impresso
Cursor := crDefault; // volta o cursor ao estado original

Apesar de aparentemente muito trabalhosa, esta impressão, depois que a pessoa se acostuma, é bem rápida, desde que sempre se utilize uma mesma resolução de desenvolvimento, pois o desenvolvedor acostuma-se com a noção de espaço horizontal e vertical e já não precisa mais efetuar diversas impressões do documento para efetuar ajustes.

Edilcimar Reis Félix – Vitória - ES


Edilcimar

Edilcimar

Responder

Posts

03/01/2006

Edilcimar

será que não estão invertidos? normalmente o comprimento de um papel é maior que a sua largura!


Responder

13/01/2006

Fabiano_aprendiz

Pergunta de quem nunca tinha visto nem usado o TPrinter: Tem como usar o TPrinter junto com um gerador de relatórios, como o Quickreport por exemplo?


Responder

13/01/2006

Edilcimar

Até onde sei não, ou usa um ou usa o outro, apesar de que o QR usa o TPrinter


Responder

13/01/2006

Fabiano_aprendiz

Pois é, eu to com um problemão, é q tenho q fazer um relatório q pode ser impresso tanto em formulário continuo como em folhas do formulário destacadas...Eu uso o quickreport e com ele eu faço os ajustes p/cada tipo de formulário(são 4 graficas diferentes p/o formulário, cada uma com suas medidas) e essa alteração pode ser feita pelo propio usuário. O problema é q uma dessas gráficas tbm utiliza o formulário continuo ,estou implementando essa opção mas tá complicado, porq qdo mando imprimir varios formularios de uma unica vz, o primeiro sai legal, mas a partir do segundo ele já salta p/o meio do segundo e por aí vai....não to sabendo como solucionar isso...


Responder

14/01/2006

Edilcimar

1) Você está pagando, portanto pode fazer com que todas as gráficas imprimam com um layout padrão em um tamanho de papel padrão
2)O fato de estar em folha solta ou papel contínuo não muda nada desde que o layout seja o mesmo
3)Você pode ter um botão para imprimir com o QR e outro para o TCanvas
4)Você pode colocar um pagesetupdialog para o usuário escolher o papel antes da impressão
5)Se está saindo direito no primeiro e não no restante, provavelmente é porque o papel não está configurado com o comprimento exato, veja que mesmo 1 mm vai dar diferença


Responder

23/01/2006

Fabiano_aprendiz

Caro Edilcimar,

E usando o WriteLn, como eu faço p/definir a posição dos campos, na vertical e horizontal?


Responder

23/01/2006

Edilcimar

para utilizar writeln(), com tabulações (controle horizontal) pegue um manual da impressora Epson (isto só servirá para impressora compatíveis com o comando ESC@) e para o controle vertical, a cada writeln() escrito ele automáticamente muda de linha, se quiser imprimir linha em branco imprima um texto em branco, para trocar de tamanho de fonte, basta olhar os mesmos comandos da impressora


Responder

25/01/2006

Fabiano_aprendiz

Caro Edilcimar,

Resolvi fazer um teste com o TPrinter, mas não estou tendo sucesso. Tenho um formulário que também foge aos padrões, o seu comprimento tem + ou - a metade de uma folha A4 portanto o comprimento é menor do que a largura mesmo. To fazendo um teste rápido, aqui segue o código:

IndiceHorizontal := Printer.PageWidth / 1010;
IndiceVertical := Printer.PageHeight / 792;
Printer.Canvas.Font.Name := ´Arial´;
Printer.Orientation := poPortrait;
Printer.BeginDoc;
Printer.Canvas.Font.Size := 10;
Linha := 20;
Table1.Open;
Table1.First;
While not Table1.Eof do
Begin
If Linha = 20 Then
begin
Coluna := Round(150 * IndiceHorizontal);
Printer.Canvas.TextOut(Coluna, Linha, Table1.FieldByName(´Nome´).AsString);
Linha := Linha + Round(20 * IndiceVertical);
Printer.Canvas.TextOut(Coluna, Linha, Table1.FieldByName(´Natureza´).AsString);
Linha := Linha + Round(20 * IndiceVertical);
Printer.Canvas.TextOut(Coluna, Linha, Table1.FieldByName(´Autor´).AsString);
Linha := Linha + Round(20 * IndiceVertical);
Printer.Canvas.TextOut(Coluna, Linha, Table1.FieldByName(´Comarca´).AsString);
Linha := Linha + Round(20 * IndiceVertical);
Printer.Canvas.TextOut(Coluna, Linha, Table1.FieldByName(´Juizo´).AsString);
Linha := Linha + Round(60 * IndiceVertical);
end;

If Linha >= 160 Then
begin
Printer.NewPage;
Linha := 20;
end;
Table1.Next;
End;
Printer.EndDoc;
Table1.Close;

Mas qdo ele da o salto para a proxima página, ele naum para na posição q eu quero, parece q continua saltando como se fosse A4. O que pode ser?
Desde já agradeço.


Responder

25/01/2006

Edilcimar

Se vc está usando um tamanho de papel não padrão, vc tem que criar pagesetupdialog para fazer isto, porque se não fizer ele vai continuar utilizando o tamanho de papel padrão que estiver definido no windows


Responder

25/01/2006

Fabiano_aprendiz

Se vc está usando um tamanho de papel não padrão, vc tem que criar pagesetupdialog para fazer isto,


Desculpe a ignorância, mas como faço p/criar esse pagesetupdialog? Poderia passar algum exemplo?


Responder

25/01/2006

Edilcimar

está na paleta dialogs do delphi
o comando é pagesetupdialog.execute


Responder

11/02/2006

Pro-luck

Caro colega,


Perdoe-me pela minha ignorância, mas ainda não consegui entender como, através do ÍndiceVertical e do ÍndiceHorizontal, poderei saber a posiçào onde os dados serao impressos... O que siginifica mesmo essas medidas: 960 e 1584...

IndiceHorizontal := Printer.PageWidth / 960;
IndiceVertical := Printer.PageHeight / 1584;


Espero poder contar com a tua colaboração, assim sendo, antecipadamente agradeço...


Responder

12/02/2006

Edilcimar

IndiceHorizontal := Printer.PageWidth / 960;
IndiceVertical := Printer.PageHeight / 1584;
estes números eu peguei da ´minha´ impressora, para o tamanho do papel que ´eu´ estou usando, estes valores vão variar de acordo com o tamanho do papel utilizado e de acordo com a resolução, assim sendo, se eu dobrar a resolução da impressora, utilizando o mesmo papel eu teria
IndiceHorizontal := Printer.PageWidth / 1920;
IndiceVertical := Printer.PageHeight / 3168;
se eu modificar o tamanho do papel então deverei modificar estes valores, portanto quando for iniciar o programa pela primeira vez, pegue estes números da sua própria impressora, dê
showmessage(´indice vertical: ´ + inttostr(printer.pageheight) + #13 + 10 + ´indice horizontal: ´ + inttostr(printer.pagewidth), assim vc ficará sabendo quais os valores no seu caso
Estes índices não são para saber ´onde´ o texto será impresso e sim para fazer a compensação de posição quando a resolução for impressa, se vc imprime em uma resolução de 300 x 300 e o seu cliente usa uma impressora com resolução de 1200 x 600, e vc não fizer isto, a impressão na impressora dele vai ficar toda ´encavalada´, ou seja as letras vão ficar amontoadas e ninguém vai conseguir ler nada, se a situação for o inverso, então as linhas vão ficar muito separadas e além de desperdiçar muito papel ainda vai ficar feio


Responder

Assista grátis a nossa aula inaugural

Assitir aula

Saiba por que programar é uma questão de
sobrevivência e como aprender sem riscos

Assistir agora

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar