Olá amigos leitores da Active Delphi. É um prazer escrever pra vocês. Prazer e tensão, porque essa é a primeira vez que publico algo.
O assunto do artigo é uma dúvida comum no mundo da programação. Muitas vezes o cliente precisa de um relatório, de uma amostra comparativa, muito extensa, mas fazer em ferramentas como Quick Report ou Rave pode nos limitar, ou dar um trabalho excessivo.
Isso quando o próprio cliente
não pergunta se é possível mandar a informação
diretamente para o Excel. Pois bem, veremos como fazer isso nesse artigo, usando
os componentes OLE da paleta “Servers” no Delphi.
Obs: para este artigo, estou usando Delphi 7 e Office 97. Mas acredito que
o que for apresentado aqui também sirva para o Office 2000.
(Atualização
do código para funcionar no Office 2003 no final do artigo)
Mãos à obra !!
Inicie uma aplicação VCL no Delphi. Adicione um Button, um
Edit, um Label (da paleta Standard), um DataSource, um ClientDataSet (ambos
da paleta Data Access), um DBGrid (da paleta Data Controls) e um ExcelApplication
(da paleta Servers). Configure os componentes da seguinte forma:
Button:
Name: btnExportar
Caption: Enviar para o Excel
Width: 115
Edit:
Name: edtNome
Label:
Caption: Digite um nome para o arquivo
ClientDataSet
Name: cdsExpExcel
FileName: C:\Arquivos de programas\Arquivos comuns\Borland Shared\Data\employee.cds
Active: True
DataSource:
DataSet: cdsExpExcel
DBGrid:
Align: alBottom
DataSource: DatSource1
ExcelApplication:
Name: Excel
Agora, dê um clique duplo no cdsExpExcel e adicione todos os campos
(“Add all fields”) contidos no arquivo. Organize os componentes
na tela de maneira que se pareça com a figura 1.
Figura1. Interface da aplicação.
Pensem agora comigo: pra exportar corretamente para o Excel, é necessário
que o programa saiba em qual coluna escrever, se na A1, B1 e assim por diante.
Por isso é necessário a criação de uma função
que faça exclusivamente isso, ou seja, que mostre em qual coluna no
Excel a informação será escrita. Ela pode ser vista a
seguir:
function TForm1.PegaLetraColuna(IntNumber : Integer) : String;
begin
if IntNumber < 1 then
Result:='A'
else
begin
if IntNumber > 256 then
Result:='IV'
else
begin
if IntNumber > 26 then
begin
Result:=Chr(64 + (IntNumber div 26));
Result:=Result+Chr(64 + (IntNumber mod 26));
end
else
Result:=Chr(64 + IntNumber);
end;
end;
end;
Repare que a função recebe um número inteiro como parâmetro
e retorna uma string. Essa função será usada dentro de
um laço, e receberá o contador do laço como parâmetro. À medida
que o contador for incrementado, a função retornará a
letra da coluna, sempre em seqüência.
Passemos agora, finalmente, para o procedimento que exportará os dados.
Veja-o na Listagem 1.
procedure TForm1.ExpExcel(Dataset : TDataSet; ArqNome : String);
var
NumLinha, NumColuna, LCID : Integer;
StrCell : String;
FileName : OleVariant;
begin
LCID := GetUserDefaultLCID;
with Excel do
begin
Connect;
try
Visible[LCID] := True;
Workbooks.Add(EmptyParam, LCID);
NumLinha := 1;
with Dataset do
begin
for NumColuna := 1 to Fields.Count do
begin
StrCell := PegaLetraColuna(NumColuna) + IntToStr(NumLinha);
if Fields[NumColuna - 1].DisplayLabel <> '' then
Range[StrCell,StrCell].Value := Fields[NumColuna - 1].DisplayLabel
else
Range[StrCell,StrCell].Value := Fields[NumColuna - 1].FieldName;
end;
end;
NumLinha := 2;
with Dataset do
begin
First;
while not Eof do
begin
for NumColuna := 1 to Fields.Count do
begin
StrCell := PegaLetraColuna(NumColuna) + IntToStr(NumLinha);
Range[StrCell, StrCell].Value := Fields.Fields[NumColuna - 1].Value;
end;
Next;
Inc(NumLinha);
end;
end;
Range['A1', StrCell].EntireColumn.Autofit;
FileName := ArqNome;
ActiveWorkbook.SaveAs(FileName, xlNormal, '', '', False, False, xlNoChange,
xlUserResolution, False, EmptyParam, EmptyParam, LCID);
Quit;
finally
Disconnect;
end;
end;
end;
Listagem 1.
Procedure para exportação para o Excel
Vamos analisar o código mais de perto:
procedure TForm1.ExpExcel(Dataset : TDataSet; ArqNome : OLEVariant);
Para poder extrair os dados, você passa como primeiro parâmetro,
o DataSet e depois o nome do arquivo externo.
Repare o seguinte: LCID, e depois LCID := GetUserDefaultLCID;
É aqui que será instanciado, chamado, o aplicativo do Excel. E
logo em seguida, em Visible[LCID] := True; ele será mostrado ao cliente.
Se você optar por não mostrar ao seu cliente o Excel, para dar uma
idéia de que sua aplicação está processando os dados, é só não
incluir essa linha no programa. Não mudará em nada.
with Excel do
begin
Connect;
Aqui o nosso programa se conectara ao servidor OLE, nesse caso o do Excel.
Workbooks.Add(EmptyParam, LCID);
Aqui será criada uma nova Pasta no Excel. (Lembrando que o Excel trata
como Pasta o arquivo que conterá as planilhas)
NumLinha := 1;
Como o Excel trabalha com coordenadas (A1, Z1500), eu inicio a minha variável
responsável por controlar o numero da linha com “1”.
for NumColuna := 1 to Fields.Count do
begin
StrCell := PegaLetraColuna(NumColuna) + IntToStr(NumLinha);
Aqui será pego as coordenadas de onde será escrito o dado. Lembrando
que começará na célula “A1”.
if Fields[NumColuna - 1]. DisplayLabel <> '' then
Range[StrCell,StrCell].Value := Fields[NumColuna - 1].DisplayLabel
else
Range[StrCell,StrCell].Value := Fields[NumColuna - 1].FieldName;
Nessa parte do código, o procedimento irá escrever o nome dos
campos do DataSet nas células (Range) da planilha do Excel. Você pode
melhorar como sairá o nome do campo, bastando para isso, quando adicionar
os campos ao DataSet, alterar a propriedade “DisplayLabel”. Note
que é passado para a célula (Range) as coordenadas de onde será escrita
a informação ([StrCell,StrCell]). Eu passo a mesma string para
inicio e fim, porque quero somente que seja escrita em uma célula. Se
quiser escrever a mesma informação em um intervalo de células,
basta colocar na seguinte notação:
Range[StrCellInicio,
StrCellFinal].Value := VarArrayOf([valor1, valor2,...
valorN]);
NumLinha := 2;
Agora eu coloco a minha variável responsável pela linha com
o valor “2”, porque na linha “1” foram escritos somente
o nome dos campos.
with Dataset do
begin
First;
while not Eof do
begin
for NumColuna := 1 to Fields.Count do
begin
StrCell := PegaLetraColuna(NumColuna) + IntToStr(NumLinha);
Range[StrCell, StrCell].Value := Fields.Fields[NumColuna - 1].Value;
end;
Next;
Inc(NumLinha);
end;
end;
Repare que o raciocínio dessa parte do código é o mesmo
que na parte anterior, com a diferença que, agora, eu precisarei mudar
de linha, somando sempre mais um à minha variável “NumLinha”.
Por isso o comando Inc(NumLinha);
Com o comando Range['A1', StrCell].EntireColumn.Autofit; eu coloco todas as colunas
com o mesmo tamanho.
ActiveWorkbook.SaveAs(ArqNome, xlNormal, '', '', False, False, xlNoChange,
xlUserResolution, False, EmptyParam, EmptyParam, LCID);
Quit;
finally
Disconnect;
A procedure “SaveAs” recebe como parâmetros o nome do arquivo
externo, o formato do arquivo (nesse caso será XLS, que é o padrão),
alguns parâmetros para tratamento do arquivo como “Password” ou
se o arquivo será de somente leitura, e por fim, a instancia aberta
do Excel (LCID).
Depois de salvar, eu fecho o Excel e me desconecto do servidor OLE.
Agora é só colocar no evento “OnClick” do btnExportar
o seguinte comando:
ExpExcel(cdsExpExcel, ExtractFilePath(Application.ExeName) + edtNome.Text);
Nesse caso, o arquivo será gerado na mesma pasta do arquivo executável.
E pronto, aí está o procedimento que exportará bonitinho
os dados do seu cliente para o Excel !!! Espero que tenham gostado dessa dica
e sobre qualquer questão, podem me contatar. Será um prazer conversar
com outros amigos Delphianos. Saúde e paz à todos nós.
Atualização
do código para funcionar no Office 2003 no final do artigo e para tratar
campos to tipo Date
Enviada pelo amigo Gustavo Frassini (usuário gustavocco)
procedure TForm1.ExpExcel(Dataset : TDataSet; ArqNome : OleVariant);
var
NumLinha, NumColuna, LCID : Integer;
StrCell : String;
// Criado Vaviaveis by Gustavo
AdtoMru, CreateBck, ROREcommended : OleVariant;
begin
LCID := GetUserDefaultLCID;
with Excel do
begin
Connect;
try
Visible[LCID] := True;
Workbooks.Add(EmptyParam, LCID);
NumLinha := 1;
(* Aqui pega o nome dos CAMPOS do Dataset *)
with Dataset do
begin
for NumColuna := 1 to Fields.Count do
begin
StrCell := PegaLetraColuna(NumColuna) + IntToStr(NumLinha);
(* Usa "DisplayLabel" das colunas para preencher as células ou "FieldName" *)
// Alterado Parametro do Range .. by Gustavo
if Fields[NumColuna - 1].DisplayLabel <> '' then
Range[StrCell,StrCell].Value2 := Fields[NumColuna - 1].DisplayLabel
else
Range[StrCell,StrCell].Value2 := Fields[NumColuna - 1].FieldName;
end;
end;
NumLinha := 2;
with Dataset do
begin
First;
while not Eof do
begin
for NumColuna := 1 to Fields.Count do
begin
StrCell := PegaLetraColuna(NumColuna) + IntToStr(NumLinha);
// Alterado Parametro do Range .. by Gustavo
if (Fields.Fields[NumColuna - 1].DataType = ftDate) or
(Fields.Fields[NumColuna - 1].DataType = ftDateTime) then
// Tratamento de Datas .. by Gustavo
if (not Fields.Fields[NumColuna - 1].IsNull) then
Range[StrCell, StrCell].Value2 := DateToStr(Fields.Fields[NumColuna - 1].AsDateTime)
else
Range[StrCell, StrCell].Value2 := ''
else
Range[StrCell, StrCell].Value2 := Fields.Fields[NumColuna - 1].Value;
end;
Next;
Inc(NumLinha);
end;
end;
Range['A1', StrCell].EntireColumn.Autofit;
// Atribuido Valor as variaveis by Gustavo
AdtoMru := False;
CreateBck := False;
ROREcommended := False;
// Alterado Parametros .. by Gustavo
ActiveWorkbook.SaveAs(ArqNome, xlnormal, EmptyParam, EmptyParam, ROREcommended, CreateBck,
xlNoChange, xlUserResolution, AdtoMru, Emptyparam, emptyparam,emptyparam, lcid);
Quit;
finally
Disconnect;
end;
end;
end;
Clique aqui para fazer o download dos exemplos.
Mini-curriculo:
Welson de Avelar Soares Filho trabalha com Delphi desde 2004. É estudante
de Ciência da Computação na Universidade Federal de Juiz
de Fora. Pode ser contatado no e-mail welson_avelar@yahoo.com.br
|