Você está na página 1de 5

Crystal Reports - emitindo cartas , usando fórmulas e tratando datas.

Para acompanhar este artigo você vai precisar ter instalado pelo menos a versão 4.6 do Crystal Reports. Vamos mostrar como emitir cartas para
aniversariantes selecionando o aniversariante e o mês desejado. Veremos também como acessar um banco de dados com senha e outras cosas mas... O
acesso aos dados será feito usando uma conexão DAO , mas você pode alterar para ADO ou RDO sem problemas...

Se você instalou o Crystal Reports na versão 5.0 do VB não terá que instalá-lo novamente quando migrar para a versão 6.0. Se você não instalou , o
Crystal Reports não é instalado automaticamente com a versão 6.0 e você vai precisar instalá-lo separadamente. Para isto inicialize o arquivo de
instalação Crystl32.exe presente no diretório \COMMON\TOOLS\VB\CRYSREPT no CD 1 do seu VB 6.0

Vamos usar um banco de dados chamado clientes.mdb e acessar a tabela Clientes de forma a selecionar os aniversariantes de um determinado mês.
A base de dados Clientes.mdb possui a senha de acesso igual a 123456.

Criando uma carta personalizada no Crystal Reports.

Podemos começar criando o relatório aniversarios.rpt no Crystal Reports:

1- Inicie o Crystal Reports

a. no Menu File selecione a opção New.


b. A seguir selecione na janela - Create New Report - o Expert - Standard
c. Na janela - Create Report Expert - clique sobre o ícone Data file , selecione o banco de dados com o qual deseja trabalhar e a seguir clique no
botão Add e depois no botão Done.

2- Na aba Fields selecione os campos da tabela para a qual deseja gera o relatorio. Usaremos apenas o campo Nome.

A estrutura da tabela Clientes é :

- ID

- Nome

- Endereço

- Telefone

- Nascimento

3- A seguir já podemos visualizar o relatório e fazer os ajustes de forma compor uma carta que será emitida para o aniversariante; clique no botão
Preview Report e a seguir na aba Design ; esconda(hide) as seções Page Header e Page Footer e faça os ajustes dispondo os campos e mensagens
na seção Details conforme indicado abaixo:

1- Aqui usaremos uma formúla que irá usar o campo Nascimento da tabela clientes para compor a data do
aniversário no formato : dia / mes de aniversário e ano ano atual : dd/mm/yyyy.

2- Iremos incluir o campo Nome da tabela Clientes para exibir o nome do aniversariante.

3- A mensagem: PARABÉNS

4- A mensagem: Muitas Felicidades e Saúde neste dia Especial

5- A mensagem: É o que lhe deseja

6- A mensagem: Toda a Equipe da

7- A mensagem: aqui você informa o nome da empresa

4- Vamos agora gerar a fórmula que irá exibir o dia e mês do aniversário e o ano atual. Para isso vamos ter que usar o campo Nascimento da tabela
Clientes. Iremos extrair deste campo o dia e o mês da data de nascimento e o ano iremos extrair da data atual. Clique na opção do menu Insert e
Formula Field, a seguir informe o nome da formula - mes - e use o código conforme figura abaixo:

Vamos explicar a fórmula:

1-ToText( Day({Clientes.Nascimento}),0) - Extraimos o dia de nascimento do campo Nascimento da tabela Clientes e convertemos o resultado em
uma string.

2-["Janeiro","Fevereiro","Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro","Dezembro"]


[Month ({Clientes.Nascimento})]

Aqui estamos extraindo um valor de uma matriz pelo indice indicado. Ex: [ 100 , 200 , 300 ] [2] irá extrair o valor 200. No nosso caso o valor
retornado por [Month ({Clientes.Nascimento})] será um número que indicará o mês de nascimento do cliente ; logo este número será o índice que
usaremos para extrair o mês correspondente da matriz. Ex:

["Janeiro","Fevereiro","Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro","Dezembro"][2] irá retornar -> Fevereiro

3-ToText (Year(today),0) - retornamos o ano da data atual e o convertemos para uma string.

Os sinais de + indicam que estamos concatenando cada parte da string gerada. Após verificar a sintaxe da fórmula coloque-a no lugar apropriado do
nosso relatório. Pronto ! podemos salvar o relatório - aniversarios.rpt. ( vamos salvar no diretório c:\teste)

Obs - Voce deve configurar a impressora na opção Selecione Printer Setup do menu File indicando a impressora a ser utilizada, lembrando que na
configuração da impressora deve estar selecionado o tamanho do papel a ser utilizado, pois o Crystal faz a leitura do setup da impressora para formatar
o relatório.

Criando o projeto no Visual Basic

Bem , agora que já temos o relatório pronto e salvo vamos criar o projeto no Visual Basic que vai usar efetivamente o relatório e permitir ao usuário a
seleção das opções.

- Inicie um novo projeto no VB e no formulário padrão - frmcartas - insira os controles e defina os títulos como na figura abaixo:

- Inclua também no seu projeto o módulo de código (.bas) com o nome de cartas.bas.

- Inclua o controle - CrystalReport1 - no seu projeto

- Não esqueça de incluir uma referência ao library DAO - Microsoft DAO 3.6 Object Library - para acesso ao banco de dados.

O que o nosso projeto vai fazer ?

a - Vamos abrir o banco de dados Clientes.mdb. Para complicar um pouco vamos atribuir uma senha ao banco de dados. A senha é 123456. Lembre-se
que a senha do banco de dados deve ser informada quando vamos abrir o arquivo. Como não vamos criar um formulário de Login teremos qu e passar a
senha para via código.

Eu vou usar os arquivos de perfis (.INI) e vou armazenar o caminho do banco de dados , a senha do banco de dados e o caminho para a localização
do relatório. Ao meu arquivo INI vou dar o nome de CONF.INI . Sua estrutura será a seguinte:

[Geral]
Caminho=C:\teste\clientes.mdb Você percebeu que a senha esta codificada?
[Senha]
Pensou que eu ia colocar a senha do banco de dados sem codificar no arquivo INI ?
Senha=365<?:
[Cartas]] Vamos ter que descodificar a senha ao passá-la para abrir o arquivo usando a rotina cripsenha.
Cartas=c:\teste

Nosso arquivo CONF.INI possui três seções : Geral , Senha e Cartas. (Leia o resumo - O que é um arquivo INI?)

b- Após abrir o banco de dados vou carregar o formulário frmcartas

c- Na carga do formulário frmcartas vamos abrir a tabela clientes e preencher as combobox - combo1 e combo2 com os nomes do clientes e com os
mês do ano respectivamente.
d- Após isto o usuário deverá selecionar o cliente e o mês para o qual deseja gerar a carta. Se não escolher um cliente iremos gerar a carta para todos
os clientes referentes ao mê informado. O mês é escolha obrigatória. Ao término basta clicar no botão Imprimir e o relatório será gerado.

A tabela clientes possui os seguintes dados. (Estou exibindo os dados para você acompanhar)

Vamos agora ao código do projeto:

Na seção General Declarations do módulo vamos declarar as variáveis visíveis em todo o projeto e as declarações API´s para ler os arquivos INI.
(Leia o artigo - Show do Zecão - que trata de arquivos INI)

Option Explicit

Public caminho As String 'guarda o caminho do banco de dados


Public senha As String 'guarda a senha do banco de dados
Public cartas As String 'guarda o caminho do relatório crystal reports

Public area As Workspace


Public db As Database

'api para leitura de arquivos de perfil (ini)


Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any,
ByVal lpFileName As String) As Long

Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String,
ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

A seguir o código da rotina Main(). Essa será a rotina que será executada primeiro quando o projeto for executado :

Sub Main()
On Error GoTo base_erro 'ativamos o tratamento de erros

If Dir(App.Path & "\conf.ini") <> "" Then


caminho = ReadINI("Geral", "Caminho", App.Path & "\conf.ini")
senha = ReadINI("Senha", "Senha", App.Path & "\conf.ini")
cartas = ReadINI("Cartas", "Cartas", App.Path & "\conf.ini")
Else
MsgBox " O ARQUIVO DE CONFIGURAÇÃO - CONF.INI - NÃO FOI LOCALIZADO !"
Exit Sub
End If

DBEngine.SystemDB = App.Path & "\system.mdw"


Set area = DBEngine.Workspaces(0)
'esta é a senha do banco de dados , não confunda com a senha do sistema de arquivos
senha = CripSenha(senha)
Set db = area.OpenDatabase(caminho, False, False, ";PWD=" & senha)

frmcartas.Show
Exit Sub

base_erro:
MsgBox Err.Description, vbCritical, "JcmSoft"
End 'uma maneira muito bruta para encerrar um aplicação
End Sub

Vamos explicar o código acima:

f Dir(App.Path & "\conf.ini") <> "" Then


caminho = ReadINI("Geral", "Caminho", App.Path & "\conf.ini")
senha = ReadINI("Senha", "Senha", App.Path & "\conf.ini")
cartas = ReadINI("Cartas", "Cartas", App.Path & "\conf.ini")
Else
MsgBox " O ARQUIVO DE CONFIGURAÇÃO - CONF.INI - NÃO FOI LOCALIZADO !"
Exit Sub
End If

- Neste código verificamos se o arquivo conf.ini esta no diretório da aplicação(Dir(App.Path & "\conf.ini") )

- Se o arquivo conf.ini existir passamos a leitura dos valores referente as chaves : Geral, Senha e Cartas; usamos para isto a função ReadINI, e ,
armazenamos os valores em variáveis com escopo Global ; caso contrário informamos ao usuário que o arquivo não existe e saimos da aplicação

- A seguir definimos a localização do arquivo do sistema - DBEngine.SystemDB = App.Path & "\system.mdw"

- Definimos uma área de trabalho padrão para o nosso ambiente - Set area = DBEngine.Workspaces(0)

- Invocamos a função CripSenha para traduzir a senha do banco de dados e armazená-la na variável senha

- Abrimos o banco de dados - Clientes.mdb - usando a localização encontrada no arquivo conf.ini (caminho) com a senha

- finalmente exibimos o formulário da aplicação - frmcartas

Agora vou mostrar o código da função ReadINI presente no arquivo de módulo - cartas.bas. ( a função para escrever em um arquivo INI - WriteINI - esta no
código , embora não a utilizemos )

Public Function ReadINI(Section As String, Key As String, FileName As String)


'Filename=nome do arquivo ini
'section=O que esta entre []
'key=nome do que se encontra antes do sinal de igual
Dim retlen As String
Dim Ret As String
Ret = String$(255, 0)
retlen = GetPrivateProfileString(Section, Key, "", Ret, Len(Ret), FileName)
Ret = Left$(Ret, retlen)
ReadINI = Ret
End Function

Este arquivo lê o arquivo de configuração conf.ini

A seguir o código da função CripSenha que encripta e descripta uma string. (esta é uma função bem simples , num artigo futuro pretendo abordar a criptografia
usando o algoritimo MD5 )

Public Function CripSenha(strSenha As String) As String


'A mesma rotina encripta e descripta
Dim nLetra$, cSenha$, L%
strSenha = Trim(strSenha)
For L = 1 To Len(strSenha)
nLetra = Asc(Mid(strSenha, L, 1))
nLetra = Chr(Trim(Str(Val(nLetra) Xor (L * 2))))
cSenha = cSenha & nLetra
Next
CripSenha = cSenha
End Function

Passemos agora para analizar o código presente no formulário - frmcartas . O primeiro código a ser executado é o código presente no evento Load do
form. O seu código é o seguinte:

Private Sub Form_Load()


dim rsclientes as recordset
Dim vetor As Variant
vetor = Array("Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro")

Set rsclientes = db.OpenRecordset("clientes", dbOpenTable)


rsclientes.Index = "CodigoID"

If rsclientes.RecordCount > 0 Then


Do While Not rsclientes.EOF
Combo1.AddItem rsclientes("nome")
Combo1.ItemData(Combo1.NewIndex) = rsclientes("ID")
rsclientes.MoveNext
Loop
Combo1.ListIndex = 0
Else
MsgBox "Não há clientes cadastrados !!!! "
Exit Sub
End If
rsclientes.Close

enche_combo Combo2, 12, vetor


Combo2.ListIndex = Month(Now) - 1

End Sub

Vejamos o significado deste código:

- Primeiro declaramos a variável objeto rsclientes do tipo Recordset e um vetor do tipo Variant:

Dim rsclientes as recordset


Dim vetor As Variant

- A seguir iniciamos o vetor com os meses do ano :

vetor = Array("Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro",
"Dezembro")

- Abrimos a tabela clientes e ativamos o índice - CodigoID - para o recordset rsclientes

Set rsclientes = db.OpenRecordset("clientes", dbOpenTable)


rsclientes.Index = "CodigoID"

- Verificamos se há registros no recordset e em caso positivo percorremos o recordset - rsclientes - preenchendo o controle combobox - combo1. Estamos usando a a propriedade
ItemData da ComboBox. Esta propriedade permite associar um número inteiro a cada item de um ComboBox ou ListBox. Ela é um vetor de valores
inteiros com o mesmo número de itens da Combo ou do ListBox , desta forma a combo exibe o nome dos clientes mas quando você selecionar um
cliente estaremos usando o seu campo ID para realizar as operações.

If rsclientes.RecordCount > 0 Then


Do While Not rsclientes.EOF
Combo1.AddItem rsclientes("nome")
Combo1.ItemData(Combo1.NewIndex) = rsclientes("ID")
rsclientes.MoveNext
Loop
Combo1.ListIndex = 0
Else
MsgBox "Não há clientes cadastrados !!!! "
Exit Sub
End If

- Fechamos o recordset clientes - rsclientes.Close

- Preenchemos o controle combobox - combo2 - invocando a função enche_combo ; esta função recebe como parâmetros o nome do controle : Combo2
, o total de itens : 12 e o vetor com o nomes a serem atribuidos. O código da função enche_combo é dado a seguir:

Public Sub enche_combo(cbo As Control, tamanho, vetor)


Dim i As Integer

For i = 0 To tamanho - 1
cbo.AddItem vetor(i)
cbo.ItemData(cbo.NewIndex) = i
Next
End Sub

Para encerrar falta somente o código do evento click do botão de comando - command1. Este código irá criar o formulário de acordo com a seleção do
usuário. Vejamos o seu código:

Private Sub Command1_Click()


Dim criterio As String
Dim periodo As String

CrystalReport1.DataFiles(0) = caminho

'relatorio de aniversarios do mes


CrystalReport1.SelectionFormula = ""
CrystalReport1.Destination = 0 'janela
CrystalReport1.ReportFileName = "aniversarios.rpt"

If Combo2.ListIndex <> -1 Then


If Combo1.ListIndex <> -1 Then
CrystalReport1.SelectionFormula = "{clientes.nome}='" & Trim(Combo1.Text) & "'"
Else
CrystalReport1.SelectionFormula = "Month({clientes.nascimento})=" & Combo2.ItemData(Combo2.ListIndex) + 1
End If
Else
MsgBox "Selecione um mês !!! "
Exit Sub
End If

CrystalReport1.Connect = "DSN=;UID=;PWD=" & senha


CrystalReport1.password = senha
CrystalReport1.Action = 1

End Sub

Vejamos o significado do código acima:

- CrystalReport1.DataFiles(0) = caminho - define a localização do banco de dados e tabelas usadas para construir o relatório. (Se você mudar o seu banco de
dados de lugar e não definir a localização do Crystal vai 'reclamar')

- No código a seguir temos :

1- Definimos a propriedade SelectionFormula como vazia


1-CrystalReport1.SelectionFormula = ""
2-CrystalReport1.Destination = 0 'janela 2- Determinamos que o relatório será exibido na tela
3-CrystalReport1.ReportFileName = "aniversarios.rpt"
3- Informamos o nome do relatório que vamos usar

- A seguir verificamos se no controle combobox - combo2 - temos um mês selecionado , se não houver seleção informamos ao usuário a mensgem -
Selecione um mês !! ; se houver , então verificamos a seguir se no controle combobox - combo1 - temos um nome selecionado; se o usuário não
selecionar um nome montamos a linha atribuindo a propriedade SelectionFormula todos os clientes com data de nascimento no mê selecionado:

- CrystalReport1.SelectionFormula = "Month({clientes.nascimento})=" & Combo2.ItemData(Combo2.ListIndex) + 1

Se o usuário informar um nome atribuimos propriedade SelectionFormula o nome do cliente indicado no combobox - combo1 :

- CrystalReport1.SelectionFormula = "{clientes.nome}='" & Trim(Combo1.Text) & "'"

- A seguir atribuimos a propriedade Connect o DSN , o nome do usuário e a senha. Como nosso banco de dados possui somente a senha , indicamos
apenas este valor. (Este parâmetro somente é requerido quando aplicado ao driver ODBC que estivermos usando. No caso estamos usando o driver ODBC para o Access.)

- Usamos a propriedade password para atribuir a senha usada no banco de dados Access. A sintaxe é :

[form.]Report.Password[= Password$]

CrystalReport1.Connect = "DSN=;UID=;PWD=" & senha


CrystalReport1.password = senha

- Para encerrar usamos a propriedade Action para disparar a execução do relatório - CrystalReport1.Action = 1

Agora acabei...Inté o próximo artigo...

José Carlos Macoratti

Você também pode gostar