access 2010_classes.pdf

134
1 Classes - Introdução Esta série de artigos tem o objetivo de apresentar o uso de classes e disseminar a utilização da orientação a objetos dentro de sistemas desenvolvidos em Access / Visual Basic for Applications. A programação orientada a objetos vem se difundindo com grande vulto no mundo todo, resolvendo problemas e causando revolução no desenvolvimento de sistemas. Ganho de produtividade e qualidade nos produtos são apenas algumas das principais características deste novo paradigma. Logo não seria muito inteligente da nossa parte, amantes do Access/VBA, nos mantermos distantes desta onda de tecnologia apenas por desconhecimento da ferramenta. Para que todos possam tirar proveito da OO (orientação a objetos) foi que nasceu a idéia de ensinar e demonstrar como criar programas com a utilização de classes no Visual Basic for Applications, a linguagem fornecida pelo MS-Access. O trabalho não será dirigido para uma versão específica do Access, mas será direcionado a todas as versões existentes, através da apresentação de conceitos e ferramentas genéricos, para que todos tenham condições de se aproveitarem dos conhecimentos aqui transmitidos. Não serão descritos nem implementados os padrões de projetos que são padrões de fato, amplamente utilizados em linguagens específicas e voltadas à POO, como Java e PHP, por exemplo. Ao contrário, será utilizado um padrão próprio para fins didáticos, também direcionados para a utilização da ferramenta case Genesis, que será tema de um dos artigos. Ao final dos artigos teremos um exemplo prático, pronto para utilização e visualização da metodologia empregada. O exemplo será um banco de dados com um pequeno sistema de vendas feito em Access com as funções totalmente implementadas utilizando classes e objetos. Além do objetivo principal dos artigos também será apresentada a utilização de uma ferramenta case, o Genesis, um sotware capaz de auxiliar na construção de um banco de dados funcional, desde a sua documentação até a criação das classes que serão utilizadas pelo sistema. O trabalho contará com 10 artigos, assim divididos: I - ORIENTAÇÃO A OBJETOS: Histórico dos paradigmas de linguagens de programação e apresentação de conceitos relativos à programação orientada a objetos; II PROGRAMAÇÃO OO NO ACCESS/VBA: Apresentação dos recursos de

Upload: lucio-mathias

Post on 05-Dec-2014

126 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: ACCESS 2010_Classes.pdf

1

Classes - Introdução

Esta série de artigos tem o objetivo de apresentar o uso de

classes e disseminar a utilização da orientação a objetos

dentro de sistemas desenvolvidos em Access / Visual

Basic for Applications.

A programação orientada a objetos vem se difundindo

com grande vulto no mundo todo, resolvendo problemas

e causando revolução no desenvolvimento de sistemas.

Ganho de produtividade e qualidade nos produtos são apenas algumas das principais

características deste novo paradigma.

Logo não seria muito inteligente da nossa parte, amantes do Access/VBA, nos

mantermos distantes desta onda de tecnologia apenas por desconhecimento da

ferramenta.

Para que todos possam tirar proveito da OO (orientação a objetos) foi que nasceu a idéia

de ensinar e demonstrar como criar programas com a utilização de classes no Visual

Basic for Applications, a linguagem fornecida pelo MS-Access.

O trabalho não será dirigido para uma versão específica do Access, mas será

direcionado a todas as versões existentes, através da apresentação de conceitos e

ferramentas genéricos, para que todos tenham condições de se aproveitarem dos

conhecimentos aqui transmitidos.

Não serão descritos nem implementados os padrões de projetos que são padrões de fato,

amplamente utilizados em linguagens específicas e voltadas à POO, como Java e PHP,

por exemplo. Ao contrário, será utilizado um padrão próprio para fins didáticos,

também direcionados para a utilização da ferramenta case Genesis, que será tema de um

dos artigos.

Ao final dos artigos teremos um exemplo prático, pronto para utilização e visualização

da metodologia empregada. O exemplo será um banco de dados com um pequeno

sistema de vendas feito em Access com as funções totalmente implementadas utilizando

classes e objetos.

Além do objetivo principal dos artigos também será apresentada a utilização de uma

ferramenta case, o Genesis, um sotware capaz de auxiliar na construção de um banco de

dados funcional, desde a sua documentação até a criação das classes que serão utilizadas

pelo sistema.

O trabalho contará com 10 artigos, assim divididos:

I - ORIENTAÇÃO A OBJETOS: Histórico dos paradigmas de linguagens de

programação e apresentação de conceitos relativos à programação orientada a objetos;

II – PROGRAMAÇÃO OO NO ACCESS/VBA: Apresentação dos recursos de

Page 2: ACCESS 2010_Classes.pdf

2

orientação a objetos presentes no Visual Basic for Applications, com a forma de

utilização e as restrições existentes;

III – MODELAGEM DO SISTEMA DE VENDAS: Definição e modelagem de um

pequeno sistema de vendas de alimentos, bastantes simples, com o desenho das classes

e suas ligações para posterior implementação;

IV – AS CLASSES AUXILIARES: Implementação das classes auxiliares, as quais

contém funções que serão necessárias para o bom funcionamento das classes principais;

V – A CLASSE CLIENTE: Definidos os itens da classe será o momento da

implementação da classe Cliente, com a codificação de todos os atributos e métodos

necessários, além da interface gráfica para manipulação dos dados;

VI – A CLASSE PRODUTO: Implementação dos atributos e métodos da classe

Produto, além da interface gráfica para manipulação dos dados;

VII – AS CLASSES VENDA E DETALHE DE VENDA: Implementação dos atributos

e métodos da classe Venda e de sua classe de ligação DetalheVenda, que será

responsável pelo controle de quais produtos fazem parte de uma venda, além da

interface gráfica para manipulação dos dados;

VIII – FINALIZAÇÃO DO SISTEMA: Finalização do sistema de vendas, com a

criação do formulário principal e dos relatórios para apresentação dos dados;

IX – GENESIS: A FERRAMENTA CASE: Apresentação do Genesis, um aplicativo

capaz de agilizar a criação de um software em Access/VBA que utiliza classes em sua

estrutura, além de produzir elementos para a documentação do sistema.

X – CONCLUSÃO: Ao final concluiremos a série de artigos apresentando alguns

apanhados sobre o uso das classes nas diferentes versões do Access e as possibilidades

de utilização da orientação a objetos para melhorar o desempenho dos sistemas

desenvolvidos.

Vamos então dar início a esta jornada de programação imergindo no mundo dos objetos

e do nosso querido Access.

Page 3: ACCESS 2010_Classes.pdf

3

Classes II - Programação OO no Access/Vba

O Visual Basic for Applications oferece suporte a apenas alguns dos recursos da

orientação a objeto. Ele permite a criação de objetos personalizados com

encapsulamento, métodos construtores e destrutores, e, inclusive, interface de classe.

Entretanto não é possível implementar a herança, uma das características mais

importantes da orientação a objetos. Como conseqüência, também não é possível

utilizar o polimorfismo real com reimplementação de métodos. O polimorfismo neste

caso se restringe a permitir que diferentes classes possam ter o mesmo nome de método,

porém com objetivos e funcionamentos diferentes.

Como já vimos o VBA não fornece suporte ao recurso da herança, então qualquer

sistema que envolva classes deve ser projetado utilizando-se cada classe implementada

inteiramente. Mesmo que possua características semelhantes a outras, a utilização dos

mecanismos de generalização/especialização não poderá ser aplicada.

Outra característica marcante da metodologia de objetos, que é implementada na

maioria das linguagens a ela direcionadas, é a sobrecarga de métodos, em que uma

mesma classe possui dois ou mais métodos com o mesmo nome. Neste caso a classe

diferencia os métodos pelo tipo e quantidade de parâmetros passados como argumento

na realização da chamada. Infelizmente esta é outra funcionalidade que o VBA não

suporta. Cada método deve ter o seu nome, diferente de todos os outros dentro da

classe.

Contudo o objetivo deste artigo é apresentar e demonstrar como criar e utilizar uma

classe simples no VBA. Por isso mesmo não serão explanados tópicos aprofundados

sobre o assunto. Caso você se interesse em conhecer um pouco mais sobre a criação de

objetos pode consultar a própria ajuda do VBA, que possui definições, explicações e

exemplos sobre todos os assuntos aqui abordados.

Criando uma Classe no VBA

Para criar uma classe no VBA basta abrir o editor, através do menu do Access ou

utilizando a combinação de teclas Alt+F11. No editor escolhemos a opção Módulo de

classe no menu Inserir da janela do editor, conforme figura abaixo:

Page 4: ACCESS 2010_Classes.pdf

4

No momento em que salvarmos a classe o nome escolhido será o nome que utilizaremos

para criar objetos desta classe. A classe do exemplo foi salva com o nome clsCliente.

Diferença Entre os Tipos de Módulos

No VBA podemos ter os seguintes tipos de módulos: Módulo Padrão, Módulo de

Formulário/Relatório e Módulo de Classe.

A diferença básica entre estes tipos de módulos está na visibilidade das informações de

cada um. Em um módulo padrão, antes chamado de módulo de código, podemos

colocar constantes, variáveis, procedimentos e funções que são diretamente acessíveis

de qualquer lugar do nosso projeto, dependendo apenas dos modificadores de acesso

utilizados. Já em um módulo de classe não é possível acessar os atributos e métodos

sem que o objeto seja instanciado.

Resumindo nós podemos chamar uma função de um módulo padrão sem que seja

preciso primeiro criar uma variável de objeto para o módulo em questão. Para funções

dentro de um módulo de classe isto não é possível.

Já o módulo de formulário/relatório trata-se apenas de um módulo de classe que

pertence ao respectivo formulário/relatório, ou seja, contém os atributos e métodos

relativos ao formulário/relatório em questão.

Os módulos padrão e de classe devem ser explicitamente criados. Já os módulos de

formulário/relatório são criados automaticamente quando criamos um formulário ou

relatório.

Page 5: ACCESS 2010_Classes.pdf

5

Então resta decidir sobre quando utilizar um módulo padrão ou um módulo de

classe. Você tem ou já teve esta dúvida? A resposta está no fato de suas variáveis e

seus procedimentos/funções serem específicos ou genéricos. Caso possam ser usados

por qualquer entidade, em qualquer módulo, a qualquer momento seria bom que

estivessem em um módulo padrão para permitir o acesso direto e imediato. Um exemplo

deste caso seria uma função que converte um valor numérico em valor por extenso.

Com certeza esta é uma função bem genérica. Já em se tratando de algo específico, que

só tenha a ver com aquele determinado objeto, por exemplo um cálculo de estoque de

uma venda, deveria ser implementado dentro da classe que modela os objetos de venda,

para que fosse acessado somente durante a existência da mesma.

Os defensores mais radicais da POO diriam que mesmo para funções genéricas deveria

ser criada uma classe para agrupar aquelas que fossem semelhantes.

Criando os Atributos da Classe

Antes de criarmos os atributos vamos incluir algumas diretivas dentro no nosso módulo

de classe para restringir a ocorrência de erros e definir o padrão de comparação de

dados no sistema. Para isto utilizamos as seguintes opções:

> Para definir o método padrão de comparação de dados dentro do módulo de classe:

Option Compare Database

> Para obrigar a declaração de variáveis dentro do módulo de classe:

Option Explicit

Obs: Estas opções não são obrigatórias na criação das classes, mas é uma boa prática

adotá-las em seus módulos. A opção de comparação deve ser aquela mais adequada ao

tipo de comparação desejada. Para maiores informações sobre estas duas opções, além

de outras, consulte a documentação do VBA.

Agora para criarmos atributos dentro da nossa classe basta declararmos as variáveis ou

constantes, lembrando que no caso destas não poderemos atribuir valores.

Como iremos declarar as variáveis diretamente no módulo, sem que estejam

subordinadas a um procedimento ou função, não poderemos fazer esta declaração

usando a instrução Dim.

Neste caso deveremos utilizar os modificadores de acesso a seguir:

Private: para atributos privados, ou seja, aqueles que não são visíveis fora do módulo.

Normalmente utilizamos este modificador e configuramos o acesso aos atributos através

dos métodos de atribuição e retorno de valores que serão vistos a seguir;

Public: para atributos públicos, ou seja, aqueles que são visíveis fora do módulo.

Conforme citado anteriormente, é uma regra da POO que os atributos não sejam

diretamente acessíveis fora da classe. Isto é o encapsulamento das informações.

Page 6: ACCESS 2010_Classes.pdf

6

Vamos criar um atributo público em nossa classe para que possamos visualizar a sua

utilização:

‘Diretivas iniciais

Option Compare Database

Option Explicit

‘Primeiro atributo: nome do cliente

Public nomeCliente As String

Salvamos a classe e agora vamos criar um módulo padrão para testar a nossa classe

criada com seu primeiro e único atributo público.

Crie um módulo padrão, salve-o com o nome de TesteClasse e inclua este código em

um procedimento chamado Teste():

{geshi lang="asp" lines="true" tit="Testando o Objeto"}Option Compare Database

Option Explicit

Sub Teste()

'Declarando o objeto cliente

Dim objCliente As New clsCliente

'Atribuindo um valor ao atributo nomeCliente

objCliente.nomeCliente = "Plinio Mabesi"

'Exibindo o valor do atributo

MsgBox "Nome do Cliente: " & objCliente.nomeCliente

End Sub{/geshi}

Perceba que assim que digitamos o ponto após o nome do objeto o VBA nos mostra

quais atributos e métodos estão disponíveis, para que possamos escolher um deles na

lista suspensa, conforme a figura abaixo:

Page 7: ACCESS 2010_Classes.pdf

7

Após o procedimento estar completo posicione o cursor dentro dele e pressione F5 para

executar. Veja o resultado apresentado na caixa de mensagem. Faça novos testes

alterando o nome do cliente e reveja o resultado.

Atributos de Classe

O VBA não fornece o recurso presente em outras linguagens em que utilizamos o

modificador Static para criar o chamado atributo de classe, o qual não depende da

instanciação do objeto para ser acessado. Ele é um atributo que não está ligado a

nenhum objeto, ou seja, ele existe sem que seja necessário declarar uma variável de

objeto da classe.

No VBA a instrução Static tem outra função: a de reter um valor de uma variável dentro

de um procedimento ou função entre as diversas chamadas. Caso não se use esta

instrução o valor de uma variável é perdido assim que o procedimento/função for

encerrado. Com a instrução Static este valor estará disponível na próxima chamada,

desde que o aplicativo ainda esteja sendo executado.

Sendo assim todos os atributos e métodos de uma classe só estarão disponíveis depois

que o objeto for instanciado.

Métodos de Acesso aos Atributos

Conforme prevê as regras da POO, não se deve fornecer acesso direto aos atributos de

um objeto, obedecendo ao conceito de encapsulamento, pois no caso de qualquer

alteração no tipo de dado ou inclusão de uma ação a ser executada quando da atribuição

ou recuperação de um valor do atributo, a classe continuará oferecendo a mesma

interface de comunicação com outras classes. Isto resulta em esforço mínimo para a

manutenção ou extensão do código.

O VBA fornece um recurso nativo e próprio para a implementação de métodos que

atribuem ou retornam valores de atributos do objeto, os conhecidos getters e setters.

Page 8: ACCESS 2010_Classes.pdf

8

São os procedimentos Property Let (atribuem valores aos atributos, equivalente ao set

em outras linguagens) e Property Get (retornam valores de atributos, equivalente ao

get das outras linguagens).

Ambos os procedimentos devem ter o mesmo nome, mas ao instanciar um objeto o

usuário tem acesso aos métodos como se fossem uma única propriedade. Para atribuir

um valor basta igualar a propriedade ao valor de uma variável, por exemplo. Da mesma

forma, para recuperar o valor de um atributo para igualar uma variável à propriedade.

Vamos alterar nossa classe para deixar o atributo protegido utilizando os procedimentos

Property Get e Property Let. O código da classe agora ficará desta maneira:

Option Compare Database

Option Explicit

'Protegendo o atributo que ficará

'visível apenas dentro da classe

Private strNomeCliente As String

Property Get nomeCliente() As String

'Retornando o valor do atributo

nomeCliente = strNomeCliente

End Property

Property Let nomeCliente(argNomeCliente As String)

'Atribuindo valor ao atributo através

'do argumento passado para o método

strNomeCliente = argNomeCliente

End Property

Perceba que alteramos o nome da variável para strNomeCliente já que os métodos se

chamarão nomeCliente. Isto deve ser feito pois o VBA não aceita que o método tenha o

mesmo nome do atributo.

Ao digitarmos o nome do objeto em um módulo qualquer veremos a lista suspensa da

mesma maneira que vimos anteriormente, com apenas uma opção de escolha, porém

desta vez quem será acessado é um dos procedimentos Property (Get ou Let) que

dependerá da ação a ser executada, sendo uma atribuição ou um retorno.

Existe também outro mecanismo, diferente de outras linguagens, utilizado para

referência a objetos. Quando um objeto possui um atributo que faz referência a outro

objeto, a atribuição é feita através do procedimento Property Set e não através do

procedimento Property Let.

Para retornar o objeto referenciado utiliza-se também o procedimento Property Get,

porém ainda faz-se necessária a utilização da instrução Set por se tratar de um objeto.

'Declarando um atributo do tipo objeto

Private objAtributoObjeto As Object

Property Get nomeDoAtributo() As Object

Page 9: ACCESS 2010_Classes.pdf

9

'Retornando o objeto

Set nomeDoAtributo = objAtributoObjeto

End Property

Property Set nomeDoAtributo(argAtributo As Object)

'Atribuindo um objeto ao atributo

Set objAtributoObjeto = argAtributo

End Property

Executando Código ao Atribuir ou Retornar Valores dos Atributos

Uma das maiores vantagens em se utilizar métodos para atribuir ou retornar valores está

na capacidade de executar códigos imediatamente antes ou após a chamada ao atributo.

Suponhamos que o nome do cliente possa ser informado em letras minúsculas ou

maiúsculas, porém desejamos que ele seja armazenado somente em maiúsculas. Neste

caso incluímos um código que faz o ajuste antes de realmente atribuir o valor:

Property Let nomeCliente(argNomeCliente As String)

'Passando o nome do cliente para maiúscula

'antes de efetivamente atribuí-lo

strNomeCliente = UCase(argNomeCliente)

End Property

Assim podemos fazer qualquer validação ou ajuste necessário antes de repassar um

valor ao atributo.

Entretanto em outra ocasião poderíamos desejar que o nome do cliente pudesse ser

informado em letras minúsculas ou maiúsculas, e que ele também possa ser armazenado

desta maneira. Porém desejamos que ao retornar o valor ele seja convertido para

maiúsculas apenas para ser apresentado. Neste caso incluímos um código que faz o

ajuste no momento de retornar o valor do atributo:

Property Get nomeCliente() As String

'Passando o nome do cliente para maiúscula

'no momento de retorná-lo ao chamador

nomeCliente = UCase(strNomeCliente)

End Property

Criando os Métodos da Classe

Para criarmos métodos basta usarmos as instruções Sub ou Function, comuns aos

outros tipos de módulos, precedidos ou não dos modificadores de acesso para

visibilidade, e os mesmos formatos de declaração, com tipos de retorno, parâmetros e

regras de nomenclatura.

Page 10: ACCESS 2010_Classes.pdf

10

Observação: Mais uma vez volto a frisar que ensinar regras de criação de

procedimentos e funções não está no escopo deste trabalho, tampouco a construção de

algoritmos, então aos interessados cabe consultar os manuais da documentação do

VBA ou as milhares de apostilas existentes na Internet. Ou quem sabe em outro artigo...

Como é do conhecimento de todos utilizamos a instrução Sub para declarar

procedimentos, ou seja, códigos que ao final de sua execução não retornam nenhum

valor. Já a instrução Function serve para declararmos funções, ou seja, códigos que ao

final devem retornar algum resultado para o chamador.

Procedimentos e funções declaradas são públicas por padrão, a não ser que se indique

explicitamente o modificador de acesso. Para este caso, além de Private e Public

podemos ainda usar o modificador Friend, o qual ajusta a visibilidade do método para

ser acessível apenas dentro do projeto atual.

Como exemplo vamos criar dois métodos em nossa classe, um que não retorna nenhum

valor e servirá para exibir os dados do cliente em uma caixa de mensagem, e outro que

deverá retornar a idade do cliente com base na sua data de nascimento. Claro que para

isto deveremos incluir o atributo data de nascimento, concorda?

Então após incluir todos os códigos em nossa classe ela estará pronta e deverá ficar

assim:

Option Compare Database

Option Explicit

'Atributos===========================================

'Nome do Cliente

Private strNomeCliente As String

'Data de Nascimento do Cliente

Private dtmDataNascimento As Date

'Métodos Property Get / Let / Set ===================

Property Get nomeCliente() As String

nomeCliente = strNomeCliente

End Property

Property Let nomeCliente(argNomeCliente As String)

strNomeCliente = UCase(argNomeCliente)

End Property

Property Get dataNascimento() As Date

dataNascimento = dtmDataNascimento

End Property

Property Let dataNascimento(argDataNascimento As Date)

dtmDataNascimento = argDataNascimento

End Property

'Métodos============================================

Page 11: ACCESS 2010_Classes.pdf

11

Sub mostraDadosCliente()

'Método que mostra o nome do

'cliente em uma caixa de mensagem

MsgBox "Nome do Cliente: " & nomeCliente & vbCrLf & _

"Data de Nascimento: " & dataNascimento & vbCrLf & _

"Idade: " & calculaIdade, vbInformation, "Dados do

Cliente"

End Sub

Function calculaIdade() As Integer

'Método que calcula a idade com

'base na data de nascimento

Dim anoAtual As Integer

Dim anoNascimento As Integer

Dim totalAnos As Integer

Dim aniversario As String

aniversario = Format(dataNascimento, "dd/mm")

anoNascimento = Year(dataNascimento)

anoAtual = Year(Date)

totalAnos = anoAtual - anoNascimento

If CDate(aniversario & "/" & anoAtual) <= Date Then

calculaIdade = totalAnos

Else

calculaIdade = totalAnos - 1

End If

End Function

Perceba que ao chamarmos o método calculaIdade() no método mostraDadosCliente()

fazemos a chamada diretamente. Isto acontece porque os dois métodos estão dentro da

mesma classe. Qualquer chamada de fora da classe somente será possível depois da

declaração da variável de objeto da classe, ou seja, depois que o objeto for instanciado.

Retornando ao nosso módulo de teste podemos observar agora que temos mais opções

na lista suspensa ao digitar o ponto após o nome do objeto:

Page 12: ACCESS 2010_Classes.pdf

12

Vamos então atribuir valores às propriedades e testar os novos métodos do objeto a

partir do procedimento Teste() em nosso módulo TesteClasse:

Option Compare Database

Option Explicit

Sub Teste()

'Declarando o objeto cliente

Dim objCliente As New clsCliente

'Atribuindo um valor ao atributo nomeCliente

objCliente.nomeCliente = "Plinio Mabesi"

'Atribuindo um valor ao atributo dataNascimento

objCliente.dataNascimento = "16/01/1976"

'Exibindo a idade do cliente em uma caixa de mensagem

MsgBox "Idade do cliente: " & objCliente.calculaIdade

'Exibindo todos os dados do cliente, mas agora

'utilizando o método próprio criado para isto

objCliente.mostraDadosCliente

End Sub

Você poderá executar o código inteiro posicionando o cursor dentro do procedimento

com a tecla F5 ou então passo a passo usando a tecla F8, podendo inclusive acompanhar

a atribuição de cada um dos valores aos atributos.

Trabalhando com Vários Objetos

Outro aspecto interessante de se trabalhar com objetos é que a partir de um único

módulo podemos criar quantos objetos forem necessários, e o que é melhor, eles podem

Page 13: ACCESS 2010_Classes.pdf

13

interagir e coexistir simultaneamente. Para isto basta declararmos cada objeto com um

nome diferente.

Vamos a um exemplo prático em nosso módulo de testes, no qual dois objetos cliente

terão as suas idades comparadas para saber quem tem mais idade, sem considerar meses

e dias:

Sub TesteIdade()

'Declarando os objetos cliente

Dim objCliente01 As New clsCliente

Dim objCliente02 As New clsCliente

'Atribuindo valores aos objetos

objCliente01.nomeCliente = "Plinio Mabesi"

objCliente01.dataNascimento = "16/01/1976"

objCliente02.nomeCliente = "Avelino Sampaio"

objCliente02.dataNascimento = "20/08/1965"

'Realizando a comparação entre os dois objetos

If objCliente01.calculaIdade = objCliente02.calculaIdade Then

MsgBox objCliente01.nomeCliente & " e " &

objCliente02.nomeCliente

& " tem a mesma idade."

ElseIf objCliente01.calculaIdade < objCliente02.calculaIdade Then

MsgBox objCliente01.nomeCliente & " é mais novo que "

& objCliente02.nomeCliente & "."

Else

MsgBox objCliente02.nomeCliente & " é mais novo que "

& objCliente01.nomeCliente & "."

End If

End Sub

Execute e veja o resultado. Altere os valores e analise o comportamento e o resultado

das variações. Tente inventar outros testes, inclua novos atributos na classe, assim como

novos métodos, use a imaginação, treine, treine e treine, pois só assim você começará a

dominar a técnica da programação orientada a objetos. Você não vai querer continuar

fora desta, vai?

Criando uma Interface de Classe

Há situações em que é interessante que algumas classes implementem certos métodos

que são padrão para todas elas. Neste caso podemos criar uma interface, que nada mais

é do que uma classe que possui métodos não implementados, que deverão ser

construídos na classe que está utilizando a interface. Por isso ela serve apenas como um

contrato de implementação, o que significa que a classe deverá obrigatoriamente possuir

aqueles métodos com os mesmos parâmetros de entrada e o mesmo tipo de dado de

Page 14: ACCESS 2010_Classes.pdf

14

retorno. Mas a classe não precisa possuir somente os métodos da interface, ela poderá

ter quantos métodos forem necessários, desde que implemente os obrigatórios.

Diferentemente de outras linguagens, no VBA uma classe totalmente implementada

pode ser interface de outras, bastando para isso incluir a instrução Implements dentro

da classe que deseja implementar a interface de outra.

Como exemplo se quiséssemos criar outra classe em nosso pequeno projeto, agora para

fornecedores, mas que obrigatoriamente tivesse que implementar todos os métodos da

nossa classe de clientes deveríamos incluir este código dentro do módulo da classe

clsFornecedor, logo no início:

Implements clsCliente

Quando inserimos a instrução Implements em uma classe o menu dropdown no editor

de código, logo abaixo da barra de ferramentas nos apresenta as opções disponíveis,

bastando selecioná-las para que sejam incluídas na classe atual. Veja a figura:

Os métodos implementados desta maneira deverão conter o nome da interface utilizada

antes do nome do método. Assim nossa classe clsFornecedor ficaria com o seguinte

aspecto, com os métodos ainda a serem implementados:

Option Compare Database

Option Explicit

Implements clsCliente

Private Property Get clsCliente_dataNascimento() As Date

End Property

Private Property Let clsCliente_dataNascimento(RHS As Date)

End Property

Private Property Let clsCliente_nomeCliente(RHS As String)

Page 15: ACCESS 2010_Classes.pdf

15

End Property

Private Property Get clsCliente_nomeCliente() As String

End Property

Private Sub clsCliente_mostraDadosCliente()

End Sub

Private Function clsCliente_calculaIdade() As Integer

End Function

É lógico e evidente que este é apenas um exemplo utilizando uma classe já pronta, e que

não serviria em uma situação real pois os nomes dos métodos foram criados para um

cliente e não para um fornecedor.

Na verdade deveríamos criar uma interface com nomes de métodos genéricos que

pudessem servir para as classes de modo geral. O método mostraDadosCliente()

poderia se chamar apenas mostraDados(). Já o método calculaIdade() está em um

padrão aceitável e poderia ser utilizado para qualquer classe que se tratasse de uma

pessoa.

Note que o próprio VBA modifica os nomes dos parâmetros de métodos que os exigem.

Porém isto não é obrigatório e você pode alterar novamente estes argumentos.

Conclusão

Aqui se encerra mais esta etapa da nossa série. Neste artigo aprendemos as técnicas

básicas para se criar uma classe no VBA, criar e proteger seus atributos, além de como

criar e utilizar os métodos da classe para oferecer funcionalidade.

Vimos também como trabalhar com mais de um objeto da classe ao mesmo tempo,

assim como tivemos uma noção sobre implementação de interfaces. Com isso

percorremos mais um trecho na caminhada rumo ao conhecimento do paradigma

orientado a objetos.

Page 16: ACCESS 2010_Classes.pdf

16

Classes III - Modelagem do Sistema de Vendas

Além disso o modelo adotado tem caráter didático e não pretende servir como um

padrão para aplicações reais. As relações criadas, as funções definidas e os atributos

escolhidos terão como objetivo maior demonstrar como funciona a aplicação da

orientação a objetos no Access / VBA, mesmo não sendo a forma mais correta e

eficiente de modelagem de classes ou de banco de dados.

Portanto preocupe-se em visualizar e compreender bem as técnicas utilizadas nas

chamadas de métodos, criação de atributos, passagem de parâmetros, enfim esteja

focado em aprender como se dá a interação entre os objetos dentro do sistema.

Padrão de Nomenclatura

O padrão que será utilizado neste trabalho obedecerá às seguintes definições:

> Não serão usados acentos, símbolos ou espaços nos nomes, já que isto é uma prática

que causa problemas na maioria das linguagens de programação existentes, não sendo

nem mesmo aceita em várias delas.

> Nomes de classes começando em maiúsculas, com o restante em minúsculas. Quando

o nome da classe for formado por mais de uma palavra elas serão separadas por

maiúscula.

Ex: Cliente, Venda, DetalheVenda;

> Nomes de atributos em minúsculas. Quando o nome do atributo for formado por mais

de uma palavra elas serão separadas por maiúscula.

Ex: cpf, nomeCliente, descricao;

> Nomes de métodos em minúsculas seguidos por parênteses. Quando o nome do

atributo for formado por mais de uma palavra elas serão separadas por maiúscula.

Ex: obter(), salvar(), consulta(), calculaClasse();

> Nomes de tabelas começando em maiúsculas, com o restante em minúsculas. Quando

o nome da tabela for formado por mais de uma palavra elas serão separadas por

maiúscula.

Ex: Cliente, Venda, DetalheVenda;

> Nomes de campos de tabelas em minúsculas. Quando o nome do campo for formado

por mais de uma palavra elas serão separadas por maiúscula.

Ex: cpf, nomeCliente, descricao;

> Nomes de consultas começando em maiúsculas, precedidos pela letra C, com o

restante em minúsculas. Quando o nome da consulta for formado por mais de uma

palavra elas serão separadas por maiúscula.

Page 17: ACCESS 2010_Classes.pdf

17

Ex: CCliente, CVenda, CDetalheVenda;

> Nomes de formulários começando em maiúsculas, precedidos pela letra F, com o

restante em minúsculas. Quando o nome do formulário for formado por mais de uma

palavra elas serão separadas por maiúscula.

Ex: FCliente, FVenda, FDetalheVenda;

> Nomes de relatórios começando em maiúsculas, precedidos pela letra R, com o

restante em minúsculas. Quando o nome o relatório for formado por mais de uma

palavra elas serão separadas por maiúscula.

Ex: RCliente, RVenda, RDetalheVenda;

Obs: No momento da implementação das classes será adicionado o prefixo cls ao nome

daquelas que dizem respeito a objetos persistentes e acl ao nome das que são

auxiliares. O motivo desta escolha será explicado no artigo sobre o Genesis, a

ferramenta case para o Access.

Modelo de Classes

Para criarmos um sistema de vendas necessitaremos dos seguintes itens básicos:

1- Os PRODUTOS que serão vendidos;

2- Os CLIENTES que irão comprar os PRODUTOS;

3- Cada grupo de PRODUTOS vendido a um CLIENTE irá gerar uma VENDA.

Então inicialmente podemos dizer que nosso sistema deverá ser capaz de manipular os

objetos Cliente, Produto e Venda. Sendo assim estas serão as classes que deveremos

modelar.

Obs: Consideraremos que já foi feito um prévio levantamento de requisitos e que já

foram definidos quais atributos e métodos as classes devem ter.

Nas interações entre os objetos poderemos perceber que:

1- Um cliente pode ser cadastrado mesmo que não tenha comprado ainda;

2- Então um cliente cadastrado pode comprar zero ou mais vezes, por isso poderão ser

realizadas

zero ou mais vendas para cada cliente;

3- Cada venda realizada deve ser feita, obrigatoriamente, a um determinado cliente;

4- Cada produto cadastrado pode estar presente ou não em uma ou mais vendas;

5- Cada venda realizada deve conter, obrigatoriamente, um ou mais produtos.

Page 18: ACCESS 2010_Classes.pdf

18

A figura abaixo ilustra então o modelo de classes referente à descrição anterior:

Para executar funções genéricas e comuns a várias classes do sistema criaremos ainda

mais duas classes, uma para realizar a conexão com banco de dados e persistir ou buscar

os objetos e outra para realizar tarefas de validação e transformação de valores, as quais

serão utilizadas pela classe Cliente. Estas serão chamadas de ConexaoBD e Utilitario.

Mas antes de definirmos o esquema básico de nossas classes temos que ajustar a relação

entre Venda e Produto. Como todos já perceberam esta é uma relação muitos-para-

muitos, então as regras de modelagem nos mandam criar uma classe de associação

para gerenciar a ligação entre elas. Portanto teremos também a classe DetalheVenda.

Estas serão as outras classes criadas para completar nosso modelo:

Descrição das Classes

A seguir serão descritas as estruturas básicas de cada uma das classes. Porém neste

artigo ainda não serão detalhadas as formas de implementação das funcionalidades de

cada método definido no modelo. Apenas a assinatura de cada método será informada,

contendo seu objetivo, seus parâmetros de entrada e seu tipo de retorno. Os métodos

Let, Get e Set também não serão abordados por enquanto.

Classe Utilitário

Objetivo: oferecer funcionalidades de validação de dados e transformação de valores,

necessárias para o correto funcionamento da classe Cliente, ou qualquer outra classe ou

função que venha a precisar dela, a qualquer momento. Isto se deve ao fato da classe

possuir métodos genéricos e reutilizáveis, podendo ser reaproveitados, sem nenhuma

alteração, em qualquer sistema.

Funções:

validaCpf(argCpf As String) As Boolean: recebe como argumento um texto contendo

um CPF, sem pontos nem traço, e devolve um valor booleano, verdadeiro ou falso,

Page 19: ACCESS 2010_Classes.pdf

19

indicando se o CPF é ou não válido;

validaEmail(argEmail As String) As Boolean: recebe como argumento um texto

contendo um e-mail e devolve um valor booleano, verdadeiro ou falso, indicando se o e-

mail é ou não válido, sendo que a verificação é feita apenas no seu formato;

nomeProprio(argNome As String) As String: recebe como argumento um texto qualquer

e devolve o mesmo texto com as iniciais dos nomes em maiúsculas e o restante em

minúsculas, levando em consideração as partículas de ligação de nomes, as quais

permanecem em minúsculas;

desacentua(argTexto As String) As String: recebe como argumento um texto qualquer e

devolve o mesmo texto sem acentos;

abreviaNome(argNome As String) As String: recebe como argumento um texto

qualquer e devolve o mesmo texto com a penúltima parte do nome abreviada, levando

em consideração as partículas de ligação de nomes, as quais permanecem inalteradas.

Classe ConexaoBD

Objetivo: oferecer funcionalidades de consulta e atualização do banco de dados. Possui

também métodos genéricos que podem ser reaproveitados em qualquer sistema. Uma

das maiores vantagens de se utilizar uma classe de conexão é que no caso de mudança

do tipo de Sistema Gerenciador de Banco de Dados (SGBD) somente ela deverá ser

alterada, permanecendo todas as outras intocadas, desde que seja mantida a interface de

comunicação dos métodos. Um exemplo seria a troca do back-end para MySql, Postgres

ou Sql Server.

Funções:

executa(codigoSql As String) As Long: recebe como argumento um texto contendo um

código SQL de inserção, exclusão ou alteração, executa o código e devolve o número de

registros afetados na operação;

consulta(codigoSql As String, Optional editavel As Boolean = False) As Recordset:

recebe como argumento um texto contendo um código SQL de consulta de registros e

um valor lógico que define o modo de bloqueio de execução, permitindo ou não a

edição dos dados durante a operação, e devolve um recordset contendo o conjunto de

registros que atenderem aos critérios;

logicoSql(ByVal argValor As Boolean) As String: recebe como parâmetro um valor

booleano e devolve um texto contendo os valores True ou False, necessário para

códigos SQL;

pontoVirgula(varValor As Variant) As String: recebe como parâmetro um valor decimal

em que o padrão de separação da parte inteira e a decimal é a vírgula, e devolve um

texto contendo o mesmo valor agora separado por ponto, necessário para códigos SQL;

dataSql(ByVal argData As Date) As String: recebe como parâmetro uma data em

qualquer formato e devolve um texto contendo a data no padrão #mm/dd/yyyy#,

Page 20: ACCESS 2010_Classes.pdf

20

necessário para códigos SQL;

valorSql(ByVal argValor As Variant) As String: recebe como parâmetro um valor

qualquer, verifica o seu formato e devolve um valor no formato padrão dos códigos

SQL, fazendo uso das funções anteriores, caso necessário.

Classe Cliente

Objetivo: oferecer funcionalidades de consulta e atualização dos objetos do tipo cliente.

Atributos:

• codCliente (Long);

• cpf (String);

• nomeCliente (String);

• email (String);

• renda (Currency);

• classe (String).

Funções:

existe(argCodCliente As Long) As Boolean: recebe como argumento um código de um

cliente, utiliza a classe de conexão para consultar e devolve um valor booleano que

indica se o cliente existe ou não no banco de dados;

incluir() As Boolean: persiste o objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso.

Este é um método privado, somente sendo acessível pelos métodos internos da classe;

obter(argCodCliente As Long) As Boolean: recebe como argumento um código de um

cliente, utiliza a classe de conexão para consultar, atualiza o objeto com os dados e

devolve um valor booleano que indica se o cliente foi buscado com sucesso;

salvar() As Boolean: salva objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso.

Este método atualiza o objeto atual caso ele já exista ou então o inclui no banco de

dados caso seja um novo objeto;

excluir() As Boolean: exclui o objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso;

calculaClasse() As String: calcula a classe social do objeto atual baseado na renda

informada e devolve uma letra correspondente à sua classificação dentro das faixas

salariais.

Classe Produto

Objetivo: oferecer funcionalidades de consulta e atualização dos objetos do tipo

produto.

Page 21: ACCESS 2010_Classes.pdf

21

Atributos:

• codProduto (Long);

• unidade (String);

• descricao (String);

• valorUnitario (Currency);

• estoqueMinimo (Double);

• qtdEstoque (Double).

Funções:

existe(argCodProduto As Long) As Boolean: recebe como argumento um código de um

produto, utiliza a classe de conexão para consultar e devolve um valor booleano que

indica se o produto existe ou não no banco de dados;

incluir() As Boolean: persiste o objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso.

Este é um método privado, somente sendo acessível pelos métodos internos da classe;

obter(argCodProduto As Long) As Boolean: recebe como argumento um código de um

produto, utiliza a classe de conexão para consultar, atualiza o objeto com os dados e

devolve um valor booleano que indica se o produto foi buscado com sucesso;

salvar() As Boolean: salva objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso.

Este método atualiza o objeto atual caso ele já exista ou então o inclui no banco de

dados caso seja um novo objeto;

excluir() As Boolean: exclui o objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso;

baixarEstoque(argQtd As Double) As Boolean: atualiza o estoque diminuindo a

quantidade informada como parâmetro e devolve um valor booleano que indica o

sucesso da operação;

subirEstoque(argQtd As Double) As Boolean: atualiza o estoque acrescentando a

quantidade informada como parâmetro e devolve um valor booleano que indica o

sucesso da operação;

estoqueBaixo() As Boolean: verifica o estoque atual e compara com o valor de estoque

mínimo cadastrado para produto e devolve um valor booleano que indica se o valor

atual está abaixo do previsto.

Classe Venda

Objetivo: oferecer funcionalidades de consulta e atualização dos objetos do tipo venda.

Atributos:

Page 22: ACCESS 2010_Classes.pdf

22

• codVenda (Long);

• codCliente (Long);

• dataVenda (Date);

Funções:

existe(argCodVenda As Long) As Boolean: recebe como argumento um código de uma

venda, utiliza a classe de conexão para consultar e devolve um valor booleano que

indica se o venda existe ou não no banco de dados;

incluir() As Boolean: persiste o objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso.

Este é um método privado, somente sendo acessível pelos métodos internos da classe;

obter(argCodVenda As Long) As Boolean: recebe como argumento um código de uma

venda, utiliza a classe de conexão para consultar, atualiza o objeto com os dados e

devolve um valor booleano que indica se o venda foi buscada com sucesso;

salvar() As Boolean: salva objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso.

Este método atualiza o objeto atual caso ele já exista ou então o inclui no banco de

dados caso seja um novo objeto;

excluir() As Boolean: exclui o objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso;

getValorTotal() As Currency: Calcula o valor total da venda atual e devolve o valor

como resultado.

Classe DetalheVenda

Objetivo: oferecer funcionalidades de consulta e atualização dos objetos de ligação

entre a venda e os produtos componentes.

Atributos:

• codVenda (Long);

• codProduto (Long);

• qtdProduto (Double);

Funções:

existe(argCodVenda As Long, argCodProduto As Long) As Boolean: recebe como

argumento um código de uma venda e de um produto, utiliza a classe de conexão para

consultar e devolve um valor booleano que indica se objeto existe ou não no banco de

dados;

incluir() As Boolean: persiste o objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso.

Este é um método privado, somente sendo acessível pelos métodos internos da classe;

Page 23: ACCESS 2010_Classes.pdf

23

obter(argCodVenda As Long, argCodProduto As Long) As Boolean: recebe como

argumento um código de uma venda e de um produto, utiliza a classe de conexão para

consultar, atualiza o objeto com os dados e devolve um valor booleano que indica se o

objeto foi buscado com sucesso;

salvar() As Boolean: salva objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso.

Este método atualiza o objeto atual caso ele já exista ou então o inclui no banco de

dados caso seja um novo objeto;

excluir() As Boolean: exclui o objeto atual no banco de dados, utilizando a classe de

conexão, e devolve um valor booleano que indica se a operação ocorreu com sucesso;

getSubTotal() As Currency: Calcula o subtotal do produto vendido para a venda atual e

devolve o valor como resultado;

getListaProduto(argCodVenda As Long) As Recordset: recebe como parâmetro um

código de uma venda e devolve um conjunto de registros contendo os códigos dos

produtos relativos à venda informada.

Diagrama de Alto Nível

Organizando as relações entre todas as classes do sistema chegamos a este modelo de

alto nível, ainda sem informações de atributos e métodos, para melhor visualização do

contexto do sistema:

Diagrama de Classes Detalhado

Incluindo agora o restante das informações de atributos e métodos chegamos a este

diagrama detalhado:

Page 24: ACCESS 2010_Classes.pdf

24

A fim de evitar sobrecarregar o modelo com informações foram omitidos os métodos de

acesso aos atributos, os Get / Let / Set, que serão incluídos apenas na implementação

das classes, nos próximos artigos. Além disso atributos auxiliares também não foram

descritos nesta etapa, mas serão incluídos no momento da implementação das classes.

Modelo de Dados

Para que um objeto seja persistente, ou seja, possa ser recuperado posteriormente, ele

deverá ser gravado em algum meio permanente. Neste caso vamos persistir nossos

objetos em um gerenciador de banco de dados bastante conhecido de todos: o próprio

Access.

Realizando o mapeamento das classes para o formato de banco dados do Access temos

então o dicionário de dados, com as informações sobre cada tabela e seus campos, além

dos relacionamentos entre elas, necessários para manter a integridade dos dados. Temos

também o diagrama de entidade-relacionamento, que é a apresentação gráfica do

dicionário. Ressalto que do nosso DER foram suprimidas as informações detalhadas dos

campos para evitar sobrecarregar o modelo, já que este também não é o foco do presente

trabalho.

Dicionário de Dados

No dicionário de dados de um modelo de dados estão descritas as informações

detalhadas sobre as tabelas, seus campos, tipos de dados, tamanho dos campos, chaves

primárias e estrangeiras, além das respectivas referências estrangeiras.

Em nosso sistema teremos as seguintes tabelas mapeadas e seus campos:

Cliente

Page 25: ACCESS 2010_Classes.pdf

25

Armazena os dados cadastrais dos clientes.

Campo Descrição Tipo

codCliente PK - Código que identifica o cliente Long(campo

chave)

cpf CPF do cliente String(11)

nomeCliente Nome completo do cliente String(50)

email E-mail do cliente String(50)

renda Renda mensal do cliente, em Reais Currency

classe Classe social do cliente, calculada de acordo com

arenda String(1)

Produto

Armazena as informações sobre os produtos.

Campo Descrição Tipo

codProduto PK - Código que identifica o produto Long(campo chave)

descricao Descrição do produto String(30)

unidade Unidade de comercialização do produto String(5)

valorUnitario Valor unitário do produto, em Reais Currency

estoqueMinimo Quantidade mínima desejada no estoque Double

qtdEstoque Quantidade atual do estoque Double

Venda

Armazena informações sobre as vendas realizadas.

Campo Descrição Tipo

codVenda PK - Código que identifica a venda Long(campo chave)

codCliente FK - Código que indica o cliente relativo à venda Long

dataVenda Data de realização da venda Date/Time

DetalheVenda

Armazena informação de ligação entre a Venda e os seus Produtos integrantes.

Campo Descrição Tipo

Page 26: ACCESS 2010_Classes.pdf

26

codProduto PK - FK - Código que indica o produto

relacionado

Long(campo chave)

FK:

Produto(codPoduto)

codVenda PK - FK - Código que indica a venda relacionada Long(campo chave)

FK: Venda(codvenda)

qtdProduto Quantidade do produto relacionado Double

Obs: PK: Primary Key (chave primária) / FK: Foreign Key (chave estrangeira)

Diagrama de Entidade-Relacionamento

Para facilitar a visualização e permitir que o modelo de dados seja melhor

compreendido o dicionário de dados é convertido em um desenho que apresenta as

tabelas e seus campos de forma gráfica. Desta maneira a percepção das relações fica

bem mais simples.

Este é o Diagrama de Entidade-Relacionamento (DER) do nosso sistema de vendas:

Assim como a modelagem de classes utilizando a UML, a modelagem do diagrama de

entidade-relacionamento não será abordado em detalhes neste curso. Então mais uma

vez para se aprofundar no assunto procure material especializado em livros ou na

Internet, ou aguarde outro artigo em um futuro próximo.

Conclusão

Este artigo teve o objetivo de iniciar realmente a construção do sistema que será objeto

de estudo desta série, através da definição de quais serão as partes componentes do

projeto.

Apesar de não nos aprofundarmos no assunto foi possível termos uma noção de

utilização de padrões de nomenclatura e da modelagem com a UML, conhecendo o

diagrama de classes e percebendo a diferença entre os níveis de visualização do sistema

pelo detalhamento das informações nos modelos.

Além disso conhecemos um pouco sobre o mapeamento das classes para o modelo

relacional, utilizando o dicionário de dados e o diagrama de entidade-relacionamento

como ferramentas.

Page 27: ACCESS 2010_Classes.pdf

27

Mesmo não abrangendo todas as etapas do desenvolvimento de um software ficou clara

a importância de se planejar bem o que deverá ser construído, através da modelagem e

da descrição dos itens, tarefa esta que faz parte da fase de análise do sistema.

Bem, como tudo já está definido a nossa etapa seguinte será colocar a mão na massa,

iniciando pela codificação das classes auxiliares, que serão úteis para o funcionamento

das restantes.

Page 28: ACCESS 2010_Classes.pdf

28

Classes IV - As Classes Auxiliares

No último artigo vimos a modelagem do sistema. Agora chegou a hora de começarmos

a codificar nossas primeiras classes.

As classes auxiliares serão responsáveis por realizar tarefas genéricas que atendem a

solicitações de diversas outras classes ou mesmo outros módulos do sistema.

Poderíamos criar inúmeras classes auxiliares, com funções agrupadas pelo tipo de tarefa

a ser realizada, assim como a classe ConexaoBD que trata de questões de conexão com

banco de dados e a classe Utilitario que contempla funções de validação e conversão de

dados.

A idéia principal aqui é a reutilização de código, um dos pilares da orientação a

objetos. Percebam que nós codificaremos a classe ConexaoBD apenas uma única vez

em toda a nossa vida. No próximo sistema que montarmos simplesmente a

importaremos para o novo software, e a classe já deverá estar pronta para ser

usada. Pode ser que a codifiquemos para outro tipo de banco de dados, por exemplo

uma ConexaoBDMySql ou uma ConexaoBDSqlServer, mas cada codificação será única

e praticamente eterna.

Vamos então rever a descrição de cada classe. Em seguida faremos a codificação. O

código das funções será apresentado apenas com comentários mas sem detalhamento, já

que (novamente) a criação de algoritmos e a estruturação de procedimentos e funções

não é o foco deste curso.

A Classe Utilitario

Objetivo: oferecer funcionalidades de validação de dados e transformação de valores,

necessárias para o correto funcionamento da classe Cliente, ou qualquer outra classe ou

função que venha a precisar dela, a qualquer momento. Isto se deve ao fato da classe

possuir métodos genéricos e reutilizáveis, podendo ser reaproveitados, sem nenhuma

alteração, em qualquer sistema.

Método validaCpf(argCpf As String) As Boolean: recebe como argumento um texto

contendo um CPF, sem pontos nem traço, e devolve um valor booleano, verdadeiro ou

falso, indicando se o CPF é ou não válido;

Function validaCPF(argCpf As String) As Boolean

'Função que verifica a validade de um CPF.

Dim wSomaDosProdutos

Dim wResto

Dim wDigitChk1

Dim wDigitChk2

Dim wStatus

Dim wI

Page 29: ACCESS 2010_Classes.pdf

29

'Inicia o valor da Soma

wSomaDosProdutos = 0

'Para posição I de 1 até 9

For wI = 1 To 9

'Soma = Soma + (valor da posição dentro do CPF x (11 - posição))

wSomaDosProdutos = wSomaDosProdutos + Val(Mid(argCpf, wI, 1)) * (11 -

wI)

Next wI

'Resto = Soma - ((parte inteira da divisão da Soma por 11) x 11)

wResto = wSomaDosProdutos - Int(wSomaDosProdutos / 11) * 11

'Dígito verificador 1 = 0 (se Resto=0 ou 1 ) ou 11 - Resto (nos casos restantes)

wDigitChk1 = IIf(wResto = 0 Or wResto = 1, 0, 11 - wResto)

'Reinicia o valor da Soma

wSomaDosProdutos = 0

'Para posição I de 1 até 9

For wI = 1 To 9

'Soma = Soma + (valor da posição dentro do CPF x (12 - posição))

wSomaDosProdutos = wSomaDosProdutos + (Val(Mid(argCpf, wI, 1)) * (12 -

wI))

Next wI

'Soma = Soma (2 x dígito verificador 1)

wSomaDosProdutos = wSomaDosProdutos + (2 * wDigitChk1)

'Resto = Soma - ((parte inteira da divisão da Soma por 11) x 11)

wResto = wSomaDosProdutos - Int(wSomaDosProdutos / 11) * 11

'Dígito verificador 2 = 0 (se Resto=0 ou 1 ) ou 11 - Resto (nos casos restantes)

wDigitChk2 = IIf(wResto = 0 Or wResto = 1, 0, 11 - wResto)

'Se o dígito da posição 10 = Dígito verificador 1 E

'dígito da posição 11 = Dígito verificador 2 Então

If Mid(argCpf, 10, 1) = Mid(Trim(Str(wDigitChk1)), 1, 1) And _

Mid(argCpf, 11, 1) = Mid(Trim(Str(wDigitChk2)), 1, 1) Then

'CPF válido

validaCPF = True

Else

'CPF inválido

validaCPF = False

End If

End Function

Método validaEmail(argEmail As String) As Boolean: recebe como argumento um

texto contendo um e-mail e devolve um valor booleano, verdadeiro ou falso, indicando

se o e-mail é ou não válido, sendo que a verificação é feita apenas no seu formato;

Function validaEmail(eMail As String) As Boolean

'Função de validação do formato de um e-mail.

Dim posicaoA As Integer

Dim posicaoP As Integer

Page 30: ACCESS 2010_Classes.pdf

30

'Busca posição do caracter @

posicaoA = InStr(eMail, "@")

'Busca a posição do ponto a partir da posição

'do @ ou então da primeira posição

posicaoP = InStr(posicaoA Or 1, eMail, ".")

'Se a posição do @ for menor que 2 OU

'a posição do ponto for menor que a posição

'do caracter @

If posicaoA < 2 Or posicaoP < posicaoA Then

'Formato de e-mail inválido

validaEmail = False

Else

'Formato de e-mail válido

validaEmail = True

End If

End Function

Método nomeProprio(argNome As String) As String: recebe como argumento um texto

qualquer e devolve o mesmo texto com as inicias dos nomes em maiúsculas e o restante

em minúsculas, levando em consideração as partículas de ligação de nomes, as quais

permanecem em minúsculas;

Function nomeProprio(argNome As String) As String

'Função recursiva para converter a primeira letra

'dos nomes próprios para maiúscula, mantendo os

'aditivos em caixa baixa.

Dim sNome As String

Dim lEspaco As Long

Dim lTamanho As Long

'Pega o tamanho do nome

lTamanho = Len(argNome)

'Passa tudo para caixa baixa

argNome = LCase(argNome)

'Se o nome passado é vazio

'acaba a função ou a recursão

'retornando string vazia

If lTamanho = 0 Then

nomeProprio = ""

Else

'Procura a posição do primeiro espaço

lEspaco = InStr(argNome, " ")

'Se não tiver pega a posição da última letra

If lEspaco = 0 Then lEspaco = lTamanho

'Pega o primeiro nome da string

sNome = Left(argNome, lEspaco)

'Se não for aditivo converte a primeira letra

If Not InStr("e da das de do dos ", sNome) > 0 Then

sNome = UCase(Left(sNome, 1)) & LCase(Right(sNome, Len(sNome) - 1))

End If

Page 31: ACCESS 2010_Classes.pdf

31

'Monta o nome convertendo o restante através da recursão

nomeProprio = sNome & nomeProprio(LCase(Trim(Right(argNome, lTamanho

- lEspaco))))

End If

End Function

Método desacentua(argTexto As String) As String: recebe como argumento um texto

qualquer e devolve o mesmo texto sem acentos ou símbolos;

Function desacentua(ByVal argTexto As String) As String

'Função que retira acentos de qualquer texto.

Dim strAcento As String

Dim strNormal As String

Dim strLetra As String

Dim strNovoTexto As String

Dim intPosicao As Integer

Dim i As Integer

'Informa as duas sequências de caracteres, com e sem acento

strAcento = "ÃÁÀÂÄÉÈÊËÍÌÎÏÕÓÒÔÖÚÙÛÜÝÇÑãáàâäéèêëíìîïõóòôöúùûüýçñ"

strNormal = "AAAAAEEEEIIIIOOOOOUUUUYCNaaaaaeeeeiiiiooooouuuuycn"

'Retira os espaços antes e após

argTexto = Trim(argTexto)

'Para i de 1 até o tamanho do texto

For i = 1 To Len(argTexto)

'Retira a letra da posição atual

strLetra = Mid(argTexto, i, 1)

'Busca a posição da letra na sequência com acento

intPosicao = InStr(1, strAcento, strLetra)

'Se a posição for maior que zero

If intPosicao > 0 Then

'Retira a letra na mesma posição na

'sequência sem acentos.

strLetra = Mid(strNormal, intPosicao, 1)

End If

'Remonta o novo texto, sem acento

strNovoTexto = strNovoTexto & strLetra

Next

'Devolve o resultado

desacentua = strNovoTexto

End Function

Método abreviaNome(argNome As String) As String: recebe como argumento um texto

qualquer e devolve o mesmo texto com a penúltima parte do nome abreviada, levando

em consideração as partículas de ligação de nomes, as quais permanecem inalteradas.

Page 32: ACCESS 2010_Classes.pdf

32

Function abreviaNome(argNome As String) As String

'Função que abrevia o penúltimo sobrenome, levando

'em consideração os aditivos de, da, do, dos, das, e.

'Define variáveis para controle de posição e para as

'partes do nome que serão separadas e depois unidas

'novamente.

Dim ultimoEspaco As Integer, penultimoEspaco As Integer

Dim primeiraParte As String, ultimaParte As String

Dim parteNome As String

Dim tamanho As Integer, i As Integer

'Tamanho do nome passado

'no argumento

tamanho = Len(argNome)

'Loop que verifica a posição do último e do penúltimo

'espaços, utilizando apenas um loop.

For i = tamanho To 1 Step -1

If Mid(argNome, i, 1) = " " And ultimoEspaco <> 0 Then

penultimoEspaco = i

Exit For

End If

If Mid(argNome, i, 1) = " " And penultimoEspaco = 0 Then

ultimoEspaco = i

End If

Next i

'Caso i chegue a zero não podemos

'abreviar o nome

If i = 0 Then

abreviaNome = argNome

Exit Function

End If

'Separação das partes do nome em três: primeira, meio e última

primeiraParte = Left(argNome, penultimoEspaco - 1)

parteNome = Mid(argNome, penultimoEspaco + 1, ultimoEspaco -

penultimoEspaco - 1)

ultimaParte = Right(argNome, tamanho - ultimoEspaco)

'Para a montagem do nome já abreviado verificamos se a parte retirada

'não é um dos nomes de ligação: de, da ou do. Caso seja usamos o método

'recursivo para refazer os passos.

'Caso seja necessário basta acrescentar outros nomes de ligação para serem

'verificados.

If parteNome = "da" Or parteNome = "de" Or parteNome = "do" Or _

parteNome = "dos" Or parteNome = "das" Or parteNome = "e" Then

abreviaNome = abreviaNome(primeiraParte & " " & parteNome) & " " &

ultimaParte

Else

abreviaNome = primeiraParte & " " & Left(parteNome, 1) & ". " & ultimaParte

End If

End Function

A Classe ConexaoBD

Page 33: ACCESS 2010_Classes.pdf

33

Objetivo: oferecer funcionalidades de consulta e atualização do banco de dados. Possui

também métodos genéricos que podem ser reaproveitados em qualquer sistema. Uma

das maiores vantagens de se utilizar uma classe de conexão é que no caso de mudança

do tipo de Sistema Gerenciador de Banco de Dados (SGBD) somente ela deverá ser

alterada, permanecendo todas as outras intocadas, desde que seja mantida a interface de

comunicação dos métodos. Um exemplo seria a troca do back-end para MySql, Postgres

ou Sql Server.

Declaração de Atributo de Banco de Dados a Nível de Classe

Criaremos um atributo que será responsável por receber e disponibilizar o banco de

dados para ser utilizado pelos métodos da classe.

'Cria um database que será utilizado para toda a classe

Private db As Database

Função logicoSql(ByVal argValor As Boolean) As String: recebe como parâmetro um

valor booleano e devolve um texto contendo os valores True ou False, necessário para

códigos SQL;

Function logicoSql(ByVal argValor As Boolean) As String

'Função que troca os valores lógicos Verdadeiro/Falso

'para True/False para utilização em consultas SQL

'Se o valor for verdadeiro

If argValor Then

'Troca por True

logicoSql = "True"

Else

'Senão troca por False

logicoSql = "False"

End If

End Function

Função pontoVirgula(ByVal varValor As Variant) As String: recebe como parâmetro

um valor decimal em que o padrão de separação da parte inteira e a decimal é a vírgula,

e devolve um texto contendo o mesmo valor agora separado por ponto, necessário para

códigos SQL;

Function pontoVirgula(ByVal varValor As Variant) As String

'Função que troca a vírgula de um valor decimal por

'um ponto para utilização em consultas SQL

Dim strValor As String

Dim strInteiro As String

Dim strDecimal As String

Dim intPosicao As Integer

'Converte o valor em string

strValor = CStr(varValor)

'Busca a posição da vírgula

intPosicao = InStr(strValor, ",")

Page 34: ACCESS 2010_Classes.pdf

34

'Se há uma vírgula em alguma posição

If intPosicao > 0 Then

'Retira a parte inteira

strInteiro = Left(strValor, intPosicao - 1)

'Retira a parte decimal

strDecimal = Right(strValor, Len(strValor) - intPosicao)

'Junta os dois novamente incluindo

'agora o ponto no lugar da vírgula

pontoVirgula = strInteiro & "." & strDecimal

Else

'Senão devolve o mesmo valor

pontoVirgula = strValor

End If

End Function

Função dataSql(ByVal argData As Date) As String: recebe como parâmetro uma data

em qualquer formato e devolve um texto contendo a data no padrão #mm/dd/yyyy#,

necessário para códigos SQL;

Function dataSql(ByVal argData As Date) As String

'Função que formata uma data para o modo SQL

'com a cerquilha: #mm/dd/yyyy#

Dim strDia As String, strMes As String, strAno As String

'Retira dia, mês e ano

strDia = Day(argData)

strMes = Month(argData)

strAno = Year(argData)

'Remonta no formato adequado

dataSql = "#" & strMes & "/" & strDia & "/" & strAno & "#"

End Function

Função valorSql(ByVal argValor As Variant) As String: recebe como parâmetro um

valor qualquer, verifica o seu formato e devolve um valor no formato padrão dos

códigos SQL, fazendo uso das funções anteriores, caso necessário;

Function valorSql(ByVal argValor As Variant) As String

'Função que formata valores para utilização

'em consultas SQL

'Seleciona o tipo de valor informado

Select Case VarType(argValor)

'Caso seja vazio ou nulo apenas

'devolve a string Null

Case vbEmpty, vbNull

valorSql = "Null"

'Caso seja inteiro ou longo apenas

'converte em string

Case vbInteger, vbLong

valorSql = CStr(argValor)

'Caso seja simples, duplo, decimal ou moeda

Page 35: ACCESS 2010_Classes.pdf

35

'substitui a vírgula por ponto

Case vbSingle, vbDouble, vbDecimal, vbCurrency

valorSql = pontoVirgula(argValor)

'Caso seja data chama a função dataSql()

Case vbDate

valorSql = dataSql(argValor)

'Caso seja string acrescenta aspas simples

Case vbString

valorSql = "'" & argValor & "'"

'Caso seja lógico chama a função logicoSql()

Case vbBoolean

valorSql = logicoSql(argValor)

End Select

End Function

Função executa(codigoSql As String) As Long: recebe como argumento um texto

contendo um código SQL de inserção, exclusão ou alteração, executa o código e

devolve o número de registros afetados na operação;

Function executa(codigoSql As String) As Long

On Error GoTo Err_executa

'Atualiza dados no Banco utilizando o código Sql passado à função,

'retornando o número de registros afetados caso a operação ocorra

'com sucesso ou 0 caso ocorra algum problema

Set db = Currentdb

db.Execute codigoSql

executa = db.RecordsAffected

Exit_executa:

Set db = Nothing

Exit Function

Err_ executa:

executa = 0

Resume Exit_executa

End Function

Função consulta(codigoSql As String, Optional editavel As Boolean = False) As

Recordset: recebe como argumento um texto contendo um código SQL de consulta de

registros e um valor lógico que define o modo de bloqueio de execução, permitindo ou

não a edição dos dados durante a operação, e devolve um recordset contendo o conjunto

de registros que atenderem aos critérios;

Function consulta(codigoSql As String, Optional editavel As Boolean = False) As

Recordset

On Error GoTo Err_consulta

'Consulta os dados no Banco utilizando o código Sql passado à função,

'retornando um recordset com o resultado da consulta

Set db = Currentdb

If editavel Then

Page 36: ACCESS 2010_Classes.pdf

36

Set consulta = db.OpenRecordset(codigoSql, , dbInconsistent, dbOptimistic)

Else

Set consulta = db.OpenRecordset(codigoSql, dbOpenSnapshot, dbReadOnly)

End If

Exit_consulta:

Set db = Nothing

Exit Function

Err_consulta:

MsgBox "Erro SQL: " & codigoSql

Set consulta = Nothing

Resume Exit_consulta

End Function

Após criar os métodos salve as classes, mas não se esqueça que para salvar

convencionamos que seria utilizado o prefixo acl para classes auxiliares. Então

salvaremos as classes com os nomes aclUtilitario e aclConexaoBD.

Instanciação dos Objetos

Com as classes já codificadas e salvas podemos instanciá-las a partir de qualquer

módulo do nosso aplicativo. Vamos fazer um teste com cada uma das classes criadas.

Para isto voltaremos ao nosso módulo padrão TesteClasse.

Primeiro a classe Utilitario. Vamos criar o procedimento TesteUtilitario:

Sub TesteUtilitario()

'Declarando o objeto da classe Utilitario

Dim objUtil As New aclUtilitario

'Testando um método da classe, convertendo um

'nome em minúsculas para o padrão de nomes próprios

'com a primeira letra maiúscula

MsgBox objUtil.nomeProprio("plinio mabesi")

End Sub

Perceba que após digitarmos o ponto depois do nome do objeto os métodos disponíveis

são listados no menu suspenso do editor do VBA.

Page 37: ACCESS 2010_Classes.pdf

37

Com isso você pode digitar o nome do método ou escolher um deles na lista suspensa.

Conforme já vimos antes para executar o código basta posicionar o cursor dentro do

procedimento e pressionar F5, ou F8 para acompanhar a execução passo-a-passo.

O resultado será uma caixa de mensagem exibindo o nome informado no formato de um

nome próprio, com as iniciais maiúsculas:

Agora a classe ConexaoBD. Vamos criar o procedimento TesteConexao:

Sub TesteConexaoBD()

'Declarando o objeto da classe ConexaoBD

Dim objCon As New aclConexaoBD

'Testando um método da classe, convertendo

'uma data para o padrão SQL

MsgBox objCon.dataSql("12/06/10")

End Sub

Assim como no objeto da classe Utilitario, ao digitarmos o ponto após o nome do

objeto da classe ConexaoBD veremos a lista suspensa com os métodos disponíveis:

Page 38: ACCESS 2010_Classes.pdf

38

Com certeza você notou que o atributo db (Database) não foi apresentado, devido ao

fato de ser um atributo privado (Private).

Perceba também que quando digitamos o primeiro parêntese após o nome do método o

editor do VBA nos mostra quais são os parâmetros exigidos, o seu tipo e o tipo de dado

de retorno do método.

No caso do método dataSql() deveremos informar o parâmetro argData que será

passado por valor (ByVal) e é do tipo Date, e teremos como retorno uma String. Veja:

Ao executarmos este procedimento teremos como resultado uma caixa de mensagem

exibindo a data informada no padrão de utilização do SQL, conforme figura abaixo.

Page 39: ACCESS 2010_Classes.pdf

39

No padrão SQL veja que o mês vem em primeiro lugar, seguido pelo dia e depois pelo

ano, tudo delimitado pela cerquilha. Todos os códigos SQL devem estar com as datas

neste formato, caso contrário ocorrerá um erro e o código não será executado.

Você não só pode como deve fazer testes com os outros métodos. Crie exemplos de

utilização para cada um deles. Se encontrar dificuldade aguarde os próximos artigos,

nos quais faremos uso intenso destas duas classes. Mesmo assim o melhor é nunca

desistir...

Conclusão

Nosso sistema começa a tomar forma de um software de verdade. Nesta etapa vimos

como codificar as classes auxiliares e tivemos uma noção de como instanciá-las para

utilizar os métodos disponibilizados.

Apesar de não ter sido detalhada a criação da estrutura dos comandos e dos algoritmos

dos métodos, os comentários o ajudarão a compreender o mínimo necessário para

produzir seus próprios códigos. Caso não tenha entendido algum trecho pesquise sobre

as funções, comandos e tipos utilizados.

Conforme salientado no início deste artigo, o principal conceito que deve ser lembrado

no momento é o da reutilização de código. A reutilização se refere a qualquer

procedimento, função ou método que possa ser diretamente empregado em qualquer

projeto imediatamente, sem necessidade de ajuste ou adaptação. Com a orientação a

objetos procuramos fazer isto com classes inteiras. As classes Utilitario e ConexaoBD

são dois exemplos de classes reutilizáveis que não requerem qualquer modificação para

funcionarem em um projeto do Access.

Claro que alguém poderia dizer que estaria faltando um ou outro método ou atributo, ou

que na verdade os métodos existentes não são os melhores, mas o importante no

momento é o conceito da reutilização e não a modelagem mais eficiente e mais correta.

Entenda que após projetar a classe mais perfeita possível e codificá-la, então ela poderá

ser distribuída para ser importada e incorporada por qualquer projeto.

Page 40: ACCESS 2010_Classes.pdf

40

Classes V - A Classe Cliente

Chegou enfim a hora de criarmos a primeira parte funcional do nosso sistema. Depois

de todo o sistema estar modelado e também estarem codificadas as classes auxiliares,

vamos então dar vida ao programa.

A primeira classe a ser codificada será a classe Cliente. Após apresentar a estrutura da

classe faremos a implementação da interface gráfica que manipulará os dados dos

objetos.

Caso necessário relembre os conceitos anteriores sobre atributos, métodos, acesso às

propriedades do objeto, instâncias e demais ensinamentos sobre a programação

orientada a objetos, vistos nos primeiros artigos.

A Classe Cliente

O objetivo desta classe, conforme dito anteriormente, é oferecer funcionalidades de

inclusão, consulta, atualização e exclusão dos objetos do tipo cliente.

Este é o código da classe, com todos os seus atributos e métodos, que se utilizam de

funções próprias, bem como dos métodos dos objetos das classes Utilitario e

ConexaoBD.

Código da classe:

Option Compare Database

Option Explicit

'Objeto da classe Utilitario

Private objUtil As New aclUtilitario

'Atributos da Classe

'Atributo de backup e atributo identificador da Classe

'PK - Código que identifica o cliente.

Private bkpCodCliente As Variant

Private lngCodCliente As Variant

'Classe social do cliente, calculada de acordo com a renda.

Private strClasse As Variant

'CPF do cliente.

Private strCpf As Variant

'E-mail do cliente.

Private strEmail As Variant

'Nome completo do cliente.

Private strNomeCliente As Variant

'Renda mensal do cliente, em reais.

Private curRenda As Variant

'Métodos Get, Set e Let da Classe

Page 41: ACCESS 2010_Classes.pdf

41

Property Get codCliente() As Variant

codCliente = lngCodCliente

End Property

Property Let codCliente(argCodCliente As Variant)

lngCodCliente = argCodCliente

If IsEmpty(bkpCodCliente) Then

bkpCodCliente = lngCodCliente

End If

End Property

Property Get classe() As Variant

classe = strClasse

End Property

Property Get cpf() As Variant

cpf = strCpf

End Property

Property Let cpf(argCpf As Variant)

If Not IsNull(argCpf) Then

If Not objUtil.validaCPF(argCpf) Then

MsgBox "O CPF <" & Format(argCpf, "000\.000\.000\-00") & _

"> não é válido.", vbExclamation, "CPF Inválido"

strCpf = Null

Else

strCpf = argCpf

End If

Else

strCpf = argCpf

End If

End Property

Property Get email() As Variant

email = strEmail

End Property

Property Let email(argEmail As Variant)

If Not IsNull(argEmail) Then

If Not objUtil.validaEmail(argEmail) Then

If MsgBox("O E-mail <" & argEmail & "> não possui um formato

válido." _

& vbCrLf & "Deseja incluir este e-mail?", vbQuestion + vbYesNo,

_

"E-mail Inválido") = vbYes Then

strEmail = argEmail

Page 42: ACCESS 2010_Classes.pdf

42

End If

Else

strEmail = argEmail

End If

Else

strEmail = argEmail

End If

End Property

Property Get nomeCliente() As Variant

nomeCliente = strNomeCliente

End Property

Property Let nomeCliente(argNomeCliente As Variant)

If Not IsNull(argNomeCliente) Then

strNomeCliente = objUtil.nomeProprio(argNomeCliente)

Else

strNomeCliente = argNomeCliente

End If

End Property

Property Get renda() As Variant

renda = curRenda

End Property

Property Let renda(argRenda As Variant)

curRenda = argRenda

'Alterar classe quando o valor da

'renda for alterado

strClasse = calculaClasse()

End Property

'Método Existe [Com conhecimento de SQL]

'Verifica a existência do objeto Cliente na tabela correspondente

'no Banco de Dados

Function existe(argCodCliente As Variant) As Boolean

On Error GoTo Err_existe

Dim objCon As New aclConexaoBD

Dim rstExiste As Recordset

Dim strSql As String

existe = False

strSql = "Select * " & _

"From Cliente " & _

"Where codCliente = " & objCon.valorSql(argCodCliente)

Set rstExiste = objCon.consulta(strSql)

If rstExiste.RecordCount > 0 Then

existe = True

Page 43: ACCESS 2010_Classes.pdf

43

End If

'Fecha o Recordset existe

rstExiste.Close

Exit_existe:

Set rstExiste = Nothing

Exit Function

Err_existe:

existe = False

GoTo Exit_existe

End Function

'Método Incluir [Com conhecimento de SQL]

'Inclui um novo objeto na tabela correspondente dentro do Banco de

dados

Private Function incluir() As Boolean

On Error GoTo Err_incluir

Dim objCon As New aclConexaoBD

Dim strSql As String

strSql = "Insert Into " & _

"Cliente(codCliente,classe,cpf,email,nomeCliente,renda) " & _

"Values(" & objCon.valorSql(codCliente) & "," _

& objCon.valorSql(classe) & "," & objCon.valorSql(cpf) _

& "," & objCon.valorSql(email) & "," &

objCon.valorSql(nomeCliente) _

& "," & objCon.valorSql(renda) & ")"

incluir = (objCon.executa(strSql) > 0)

If incluir Then

'Atualiza os campos de backup

bkpCodCliente = codCliente

End If

Exit_incluir:

Exit Function

Err_incluir:

incluir = False

GoTo Exit_incluir

End Function

'Método Excluir [Com conhecimento de SQL]

'Exclui o objeto atual na tabela correspondente dentro do Banco de

dados

Function excluir() As Boolean

On Error GoTo Err_excluir

Dim objCon As New aclConexaoBD

Dim strSql As String

strSql = "Delete From Cliente " & _

"Where codCliente = " & objCon.valorSql(codCliente)

excluir = (objCon.executa(strSql) > 0)

Page 44: ACCESS 2010_Classes.pdf

44

Exit_excluir:

Exit Function

Err_excluir:

excluir = False

GoTo Exit_excluir

End Function

'Método Obter [Com conhecimento de SQL]

'Recupera o objeto Cliente através dos argumentos informados

Function obter(argCodCliente As Variant) As Boolean

On Error GoTo Err_obter

Dim objCon As New aclConexaoBD

Dim rstObter As Recordset

Dim strSql As String

strSql = "Select * " & _

"From Cliente " & _

"Where codCliente = " & objCon.valorSql(argCodCliente)

Set rstObter = objCon.consulta(strSql)

If rstObter.RecordCount = 0 Then

obter = False

Exit Function

End If

'Atualiza os campos de backup e os identificadores

codCliente = argCodCliente

bkpCodCliente = argCodCliente

'Atualiza os campos restantes

strClasse = rstObter.Fields("classe")

cpf = rstObter.Fields("cpf")

strEmail = rstObter.Fields("email")

nomeCliente = rstObter.Fields("nomeCliente")

renda = rstObter.Fields("renda")

obter = True

'Fecha o Recordset obter

rstObter.Close

Exit_obter:

Set rstObter = Nothing

Exit Function

Err_obter:

obter = False

MsgBox Err.Description

GoTo Exit_obter

End Function

'Método Salvar [Com conhecimento de SQL]

'Salva o objeto atual na tabela correspondente dentro do Banco de

dados

Page 45: ACCESS 2010_Classes.pdf

45

Function salvar() As Boolean

On Error GoTo Err_salvar

Dim objCon As New aclConexaoBD

Dim strSql As String

If existe(bkpCodCliente) Then

strSql = "Update Cliente " & _

"Set codCliente = " & objCon.valorSql(codCliente) _

& ", classe = " & objCon.valorSql(classe) _

& ", cpf = " & objCon.valorSql(cpf) & ", email = " _

& objCon.valorSql(email) & ", nomeCliente = " _

& objCon.valorSql(nomeCliente) & ", renda = " _

& objCon.valorSql(renda) _

& " Where codCliente = " & objCon.valorSql(bkpCodCliente)

salvar = (objCon.executa(strSql) > 0)

Else

salvar = incluir

End If

If salvar Then

'Atualiza as variáveis de backup com o novo valor da chave

bkpCodCliente = codCliente

End If

Exit_salvar:

Exit Function

Err_salvar:

salvar = False

GoTo Exit_salvar

End Function

'Método calculaClasse

'Calcula a classe social do objeto atual baseado na

'renda informada e devolve uma letra correspondente

'à sua classificação dentro das faixas salariais.

Private Function calculaClasse() As String

If renda >= 15300 Then

calculaClasse = "A"

ElseIf renda >= 7650 Then

calculaClasse = "B"

ElseIf renda >= 3060 Then

calculaClasse = "C"

ElseIf renda >= 1020 Then

calculaClasse = "D"

ElseIf renda > 0 Then

calculaClasse = "E"

Else

calculaClasse = ""

End If

End Function

'Fim da classe...

Pontos Importantes

Page 46: ACCESS 2010_Classes.pdf

46

Nesta primeira classe referente a um objeto atualizável, com atributos modificáveis,

passíveis de serem persistidos, podemos notar alguns pontos de interesse para o

aprendizado da metodologia, conforme a seguir.

1. Atributos do tipo Variant: Como podemos encontrar objetos cujos campos não são

de preenchimento obrigatório devemos manter a possibilidade de atribuir valores nulos

aos atributos dos objetos, os quais serão reconhecidos pelo método valorSql(), da classe

ConexaoBD, e convertidos da maneira correta para armazenagem na tabela. Caso

utilizássemos atributos com os tipos pré-definidos não teríamos como reconhecer um

atributo nulo de maneira tão fácil. Neste caso teríamos que procurar métodos

alternativos de convenção e tratamento de valores que representariam a nulidade de

atributos, como por exemplo uma seqüência de comprimento zero em uma string, ou um

valor negativo que provavelmente nunca seria atribuído a um campo de código para

chave primária, entre outros. Contudo, para o nosso projeto, contando com a facilidade

da atribuição de valores e seus tipos às variáveis do tipo Variant, e a funcionalidade do

método valorSql() esta será a forma que adotaremos.

'Nome completo do cliente.

Private strNomeCliente As Variant

2. Criação do atributo de backup do objeto: Apesar de não ser necessário quando se

usa atributos identificadores do tipo auto-numeração, esta é uma técnica que possibilita

a alteração do código identificador do objeto permitindo salvar as modificações

posteriormente, já que o antigo valor, que continua armazenado no banco de dados,

ainda estará disponível no atributo de backup. Quando se usa qualquer tipo de código

personalizado como a chave primária este recurso torna-se indispensável.

'Atributo de backup e atributo identificador da Classe

'PK - Código que identifica o cliente.

Private bkpCodCliente As Variant

Private lngCodCliente As Variant

3. Validação de dados no momento da atribuição do valor: Neste caso podemos

visualizar na prática como validar um dado antes de atribuí-lo ao objeto. Como exemplo

verificamos a validade de um CPF fornecido pelo usuário, permitindo ou não a sua

utilização. Esta é uma tarefa que evita falhas de digitação e incorreções nos dados

armazenados.

Property Let cpf(argCpf As Variant)

If Not IsNull(argCpf) Then

If Not objUtil.validaCPF(argCpf) Then

MsgBox "O CPF <" & Format(argCpf, "000\.000\.000\-00") _

& "> não é válido.", vbExclamation, "CPF Inválido"

strCpf = Null

Else

strCpf = argCpf

End If

Else

strCpf = argCpf

End If

End Property

Page 47: ACCESS 2010_Classes.pdf

47

4. Conversão de dados no momento da atribuição do valor: Neste caso podemos

visualizar na prática como alterar um dado fornecido pelo usuário antes de atribuí-lo ao

objeto. Esta tarefa é útil na padronização das informações armazenadas. Como exemplo

armazenamos todos os nomes dos clientes no padrão de nomes próprios, com a primeira

letra de cada parte do nome em maiúsculas e o restante em minúsculas. Esta

funcionalidade é oferecida pelo método nomeProprio() da classe Utilitario,

representada pelo objeto objUtil.

Property Let nomeCliente(argNomeCliente As Variant)

If Not IsNull(argNomeCliente) Then

strNomeCliente = objUtil.nomeProprio(argNomeCliente)

Else

strNomeCliente = argNomeCliente

End If

End Property

5. Determinação de uma propriedade baseada em outra: Apesar de não ser uma boa

prática e estar diretamente contra as Formas Normais, esta funcionalidade foi colocada

apenas para servir de exemplo. Aqui determinamos a classe social a que o cliente

pertence a partir da sua renda informada. Para isto utilizamos o método calculaClasse()

da própria classe Cliente. A informação é atribuída à propriedade classe e armazenada

no banco de dados, lembrando mais uma vez que esta não é uma prática recomendada

em sistemas profissionais.

Property Let renda(argRenda As Variant)

curRenda = argRenda

'Alterar classe quando o valor da

'renda for alterado

strClasse = calculaClasse()

End Property

6. Ajuste de código SQL: Para que possamos montar nossas classes sem nos preocupar

com o formato SQL dos dados, utilizamos a classe ConexaoBD e seus métodos para

fazer todos os ajustes e nos deixar resolver os problemas mais sérios, que requerem

nossa atenção. Veja que para nós não será necessário descobrir se o atributo e do tipo

texto, data ou numérico. O método valorSql() se encarrega disto. Aqui a classe está

representada pelo objeto objCon.

strSql = "Select * " & _

"From Cliente " & _

"Where codCliente = " & objCon.valorSql(argCodCliente)

7. Atributo classe: Para o cálculo da classe social a partir da renda foi utilizada uma

tabela fictícia de exemplo, a qual não representa fielmente os valores publicados pelos

órgãos competentes.

Outra funcionalidade importante que podemos encontrar nos códigos é o tratamento de

erros com a instrução On Error. Apesar de não ser detalhado neste curso é altamente

recomendado que o leitor pesquise e compreenda a sua utilização. Foram colocados

exemplos simples nos métodos, porém o correto entendimento deste recurso possibilita

Page 48: ACCESS 2010_Classes.pdf

48

alta capacidade de resolução de problemas na programação, evitando que possíveis e

prováveis erros no projeto ou na implementação sejam visíveis para o usuário final de

maneira inadequada.

Mais Funções Auxiliares

Neste projeto não utilizaremos códigos com auto-numeração diretamente nas tabelas.

Sendo assim necessitaremos de uma função que realize esta tarefa.

Criaremos então um módulo padrão que conterá todas as funções auxiliares que

necessitarmos durante o curso. Ele se chamará Funcoes e nossa primeira função será

chamada proximoCodigo().

Este será o código da função:

Function proximoCodigo(argCampo As String, argTabela As String, _

Optional criterio As String = "") As Long

proximoCodigo = Nz(DMax(argCampo, argTabela, criterio), 0) + 1

End Function

Ela receberá como parâmetros o nome do campo, o nome da tabela e um critério de

busca opcional, devolvendo um número que será o próximo código livre daquele campo

numérico da tabela informada.

Desta maneira a função será genérica e servirá para qualquer tabela que contenha um

campo chave de código numérico ordenado.

A Interface Gráfica

Para que possamos visualizar e manipular os dados dos clientes devemos criar um

formulário com campos para preenchimento e botões de comando que coordenem as

ações sobre os dados.

A seguir serão definidas as características para o formulário no qual iremos trabalhar

com os dados dos objetos relativos aos clientes. As especificações de design são apenas

sugestões, porém as informações de origem de dados, bloqueio de campos e formatos de

dados são obrigatórias, sob pena de não obter a funcionalidade desejada. Estas

especificações estarão marcadas com um asterisco vermelho ao lado.

No formulário teremos uma lista contendo os clientes cadastrados, um campo de texto

para realizar buscas, alguns campos de texto para digitação das informações e os botões

de comando para criar, salvar e excluir registros.

Obs: Somente as propriedades que foram alteradas para um valor diferente do padrão

serão apresentadas. Para as demais utilize o padrão do sistema ou o valor que desejar,

desde que não comprometa a funcionalidade do sistema.

Formulário

Nome: FCliente

Largura: 20cm

Page 49: ACCESS 2010_Classes.pdf

49

Altura: Cabeçalho (1cm) / Detalhe (10cm)

Legenda: Sistema de Vendas

Estilo da borda: fino

Seletores de registro: Não

Botões de navegação: Não

Linhas divisórias: Não

Barras de rolagem: Nenhuma

Caixa de controle: Sim

Botão Fechar: Sim

Botões Min Max: Nenhum

Popup: Sim

Janela Restrita: Não

Controle Listbox

Nome: lstCliente *

Origem da linha: SELECT Cliente.codCliente, Cliente.nomeCliente,

Format(Cliente.cpf,"000\.000\.000-00") AS cpf FROM

Cliente

ORDER BY Cliente.nomeCliente; *

Tipo de Origem da Linha: Tabela/Consulta *

Coluna acoplada: 1 *

Número de colunas: 3 *

Largura das colunas: 0cm;5cm;3cm *

Largura: 8cm

Cor do fundo: Cinza claro

Controles Textbox

Nome: txtPesquisa *

Cor do fundo: Amarelo

Alinhamento: Esquerda

Nome: txtCodigo *

Ativado: Não *

Bloqueado: Sim *

Cor do fundo: Cinza

Alinhamento: Centro

Nome: txtCpf *

Cor do fundo: Azul claro

Máscara de entrada: 000.000.000\-00;;_ *

Alinhamento: Centro

Nome: txtNome *

Cor do fundo: Azul claro

Alinhamento: Esquerda

Nome: txtEmail *

Cor do fundo: Azul claro

Alinhamento: Esquerda

Nome: txtRenda *

Cor do fundo: Azul claro

Alinhamento: Direita

Formato: Unidade Monetária

Nome: txtClasse *

Ativado: Não *

Page 50: ACCESS 2010_Classes.pdf

50

Bloqueado: Sim *

Cor do fundo: Cinza

Alinhamento: Centro

Botões de Comando

Nome: btnNovo *

Legenda: Novo

Cor da Fonte: Azul escuro

Nome: btnSalvar *

Legenda: Salvar

Cor da Fonte: Azul escuro

Nome: btnExcluir *

Legenda: Excluir

Cor da Fonte: Vermelho escuro

Como sugestão de design os campos deverão estar posicionados conforme demonstrado

na figura a seguir, assim como devem ser adicionadas as legendas dos campos, as quais

não foram descritas anteriormente:

Códigos do Formulário

Para que nosso formulário seja capaz de manipular os dados dos objetos cliente

deveremos implementar as funcionalidades necessárias que permitam criar um novo

cliente, buscar um cliente já cadastrado, editar seus dados, salvá-lo ou excluí-lo.

Sendo assim criaremos algumas funções genéricas que sejam úteis para quantos

procedimentos delas necessitem, reaplicando o conceito da reutilização de código. Além

Page 51: ACCESS 2010_Classes.pdf

51

disso incluiremos os códigos dos campos que possuem eventos, além dos botões de

comando.

Todos os códigos a seguir deverão ser colocados no módulo do formulário FCliente.

1. Pesquisa de clientes: Para facilitar a busca de clientes por qualquer parte do nome

utilizaremos um campo de texto cujo valor será o elemento condicional para o código

SQL que será atribuído ao controle lstCliente, atualizando sua propriedade Origem da

Linha após cada alteração realizada no campo de pesquisa. Para isto devemos colocar o

código no evento Ao Alterar do campo txtPesquisa.

Private Sub txtPesquisa_Change()

lstCliente.RowSource = "SELECT Cliente.codCliente,

Cliente.nomeCliente, " & _

"Format(Cliente.cpf,'000\.000\.000-00') AS cpf " & _

"FROM Cliente " & _

"WHERE nomeCliente Like '*" & txtPesquisa.Text & "*' " &

_

"ORDER BY Cliente.nomeCliente;"

lstCliente.Requery

End Sub

2. Limpeza dos campos: Para efetuar a limpeza dos campos de preenchimento

utilizaremos um procedimento genérico cuja função será a de atribuir o valor nulo a

todos os campos de texto e enviar o foco ao campo txtCpf.

Private Sub limpaCampos()

txtCodigo = Null

txtCpf = Null

txtNome = Null

txtEmail = Null

txtRenda = Null

txtClasse = Null

txtCpf.SetFocus

End Sub

3. Novo registro: Para a criação de um novo registro em branco simplesmente iremos

chamar o procedimento limpaCampos() no evento Ao Clicar do botão btnNovo.

Private Sub btnNovo_Click()

Call limpaCampos

End Sub

4. Atualização de campos: Assim como fizemos um procedimento genérico que limpa

os campos para a criação de um novo registro teremos também um que preencha os

campos com as informações de um objeto cliente passadas como parâmetro, ou seja, o

procedimento recebe um objeto completo e lança os valores de seus atributos nos

campos do formulário.

Private Sub atualizaCampos(argCliente As clsCliente)

Page 52: ACCESS 2010_Classes.pdf

52

txtCodigo = argCliente.codCliente

txtCpf = argCliente.cpf

txtNome = argCliente.nomeCliente

txtEmail = argCliente.email

txtRenda = argCliente.renda

txtClasse = argCliente.classe

End Sub

5. Escolha de cliente: Já que teremos também que trabalhar com clientes já

cadastrados, devemos implementar alguma maneira de recuperar suas informações.

Faremos isto utilizando a Listbox lstCliente, que utilizará o procedimento

atualizaCampos() para preencher os campos com as informações do objeto do cliente

que foi clicado.

Private Sub lstCliente_Click()

Dim objCliente As New clsCliente

Dim codigoCliente As Long

codigoCliente = lstCliente.Value

If objCliente.obter(codigoCliente) Then

Call atualizaCampos(objCliente)

End If

End Sub

6. Montagem de um objeto: Esta também é uma função genérica que será utilizada por

outros procedimentos ou funções. Seu objetivo é criar um novo objeto cliente, coletar os

dados digitados nos campos, atribuir ao objeto criado, e devolvê-lo para quem chamou a

função.

Private Function buscaCampos() As clsCliente

Set buscaCampos = New clsCliente

If IsNull(txtCodigo) Then

txtCodigo = proximoCodigo("codCliente", "Cliente")

End If

buscaCampos.codCliente = txtCodigo

buscaCampos.cpf = txtCpf

buscaCampos.nomeCliente = txtNome

buscaCampos.email = txtEmail

buscaCampos.renda = txtRenda

End Function

7. Salvando um cliente: Depois de informados os dados de um novo cliente, ou

alterados os dados de um cliente já cadastrado, necessitaremos de um procedimento que

efetue a gravação destes dados. Para isto o botão btnSalvar conterá o código necessário

no evento Ao Clicar. Ele fará uso da função buscaCampos(), a qual montará o objeto a

ser salvo, e também o método salvar() do objeto, apresentando uma mensagem ao

usuário com o resultado da operação. Após salvar os dados de um cliente também

Page 53: ACCESS 2010_Classes.pdf

53

deveremos atualizar a Listbox para que apresente estes dados, sejam eles novos ou

apenas alterados.

Private Sub btnSalvar_Click()

Dim objCliente As clsCliente

If Not IsNull(txtCpf) And Not IsNull(txtNome) Then

Set objCliente = buscaCampos

If objCliente.salvar Then

MsgBox "O cliente foi salvo com sucesso.", vbInformation, _

"Salvar Cliente"

lstCliente.Requery

Call atualizaCampos(objCliente)

Else

MsgBox "Ocorreu um erro durante o salvamento.", vbExclamation, _

"Salvar Cliente"

End If

Else

MsgBox "Informe os dados do cliente.", vbExclamation, "Salvar

Cliente"

End If

End Sub

8. Excluindo um cliente: Além de criar e alterar os dados de um cliente, é importante

que também possamos excluí-lo definitivamente de nosso cadastro. Logo devemos

também implementar a funcionalidade para o botão btnExcluir, que conterá o código

necessário também no evento Ao Clicar. Ele também deverá fazer uso da função

buscaCampos() para a montagem do objeto a ser excluído, pois caso contrário a classe

não saberá que objeto deve ser excluído. Em seguida utilizaremos o método excluir() do

objeto, apresentando uma mensagem ao usuário com o resultado da operação. É claro

que após excluir um cliente também deveremos atualizar a Listbox para que a mesma

reflita as alterações realizadas.

Private Sub btnExcluir_Click()

Dim objCliente As clsCliente

If Not IsNull(txtCodigo) Then

If MsgBox("Confirma a exclusão do registro?", vbQuestion +

vbYesNo, _

"Excluir Cliente") = vbYes Then

Set objCliente = buscaCampos

If objCliente.excluir Then

MsgBox "O registro foi excluído com sucesso.", vbInformation,

_

"Excluir Cliente"

lstCliente.Requery

Call limpaCampos

Else

MsgBox "Ocorreu um erro durante a exclusão.", vbExclamation, _

"Excluir Cliente"

End If

Page 54: ACCESS 2010_Classes.pdf

54

End If

End If

End Sub

Estes são os procedimentos e funções básicas para que a interface possa manipular os

objetos. Não se esqueça de que para efetuar os testes deveremos utilizar um CPF válido

devido à verificação realizada.

Sistema de Exemplo

A partir deste artigo será disponibilizado o link para download do sistema de vendas no

estado de desenvolvimento em que se encontrar o projeto.

Recomendo aos estudiosos desenvolvedores que o consultem apenas para tirar dúvidas e

realizar comparações. Aqueles que realmente quiserem aprender façam toda a

codificação e a montagem das telas manualmente. Somente assim a sua mente irá se

defrontar com as dificuldades do processo e assimilará os passos necessários para a

resolução dos problemas e a conclusão dos objetivos.

Segue o link para download:

Venda00.zip

Como ainda não há uma tela principal abra o formulário FCliente diretamente na janela

Banco de Dados (Access 2003-) ou no Painel de Navegação (Access 2007+).

Conclusão

Enfim demos início à parte mais empolgante do curso, na qual podemos ver o sistema

realmente operando, manipulando os objetos. Pudemos ver como se dá a interação entre

objetos, a verificação de atributos, a montagem de códigos SQL para busca, alteração,

inserção e exclusão de dados, além de visualizar procedimentos simples de tratamento

de erros.

Nunca é demais relembrar que o objetivo maior de todas as etapas do curso é apresentar

de forma didática, da maneira mais simples possível, a utilização de objetos em projetos

do Access/VBA. Sendo assim não considere as implementações apresentadas como o

padrão de fato da programação. Muita coisa foi simplesmente omitida ou modificada,

mesmo partindo dos próprios padrões que utilizo em meus projetos reais para que fosse

alcançada a objetividade necessária ao entendimento por parte de usuários iniciantes ou

com pouca experiência na POO.

A lição mais importante deste artigo foi realmente a visualização da dinâmica da

utilização dos objetos na manipulação de informações, tanto na sua apresentação quanto

na sua persistência.

A partir deste momento, creio, ficará cada vez mais fácil a percepção da operação com

objetos, desde que o leitor compreenda bem o que foi visto até agora, pois estes

Page 55: ACCESS 2010_Classes.pdf

55

conceitos iniciais são a base da orientação a objetos. Apesar de não contarmos com as

outras faces da OO, como a herança por exemplo, com certeza a mente do leitor já

começará a visualizar melhor as infinitas possibilidades que a metodologia

fornece. Porém relembro que para conseguir dominar a técnica é imprescindível

continuar treinando, criando seus próprios códigos, fazendo experiências, resolvendo

problemas com a aplicação do paradigma, lendo outros materiais e compartilhando

conhecimento, seja com colegas de trabalho, amigos ou em fóruns sobre o assunto.

Page 56: ACCESS 2010_Classes.pdf

56

Classes VI - A Classe Produto

Continuando a inclusão de funcionalidade em nosso sistema vamos agora ao próximo

passo.

A próxima classe a ser codificada será a classe Produto. Após apresentar a estrutura da

classe faremos a implementação da interface gráfica que manipulará os dados dos

objetos.

Mais uma vez, caso necessário, relembre os conceitos anteriores sobre atributos,

métodos, acesso às propriedades do objeto, instâncias e demais ensinamentos sobre a

programação orientada a objetos, vistos nos primeiros artigos.

A Classe Produto

O objetivo desta classe, conforme dito anteriormente, é oferecer funcionalidades de

inclusão, consulta, atualização e exclusão dos objetos do tipo produto.

Este é o código da classe, com todos os seus atributos e métodos, que se utilizam de

funções próprias, bem como dos métodos do objeto da classe ConexaoBD.

Código da classe:

Option Compare Database

Option Explicit

'Atributos da Classe

'Atributo de backup e atributo identificador da Classe

'PK - Código que identifica o produto.

Private bkpCodProduto As Variant

Private lngCodProduto As Variant

'Descrição do produto.

Private strDescricao As Variant

'Quantidade mínima desejada no estoque.

Private dblEstoqueMinimo As Variant

'Quantidade atual do estoque.

Private dblQtdEstoque As Variant

'Unidade de comercialização do produto.

Private strUnidade As Variant

'Valor unitário do produto.

Private curValorUnitario As Variant

'Métodos Get, Set e Let da Classe

Property Get codProduto() As Variant

Page 57: ACCESS 2010_Classes.pdf

57

codProduto = lngCodProduto

End Property

Property Let codProduto(argCodProduto As Variant)

lngCodProduto = argCodProduto

If IsEmpty(bkpCodProduto) Then

bkpCodProduto = lngCodProduto

End If

End Property

Property Get descricao() As Variant

descricao = strDescricao

End Property

Property Let descricao(argDescricao As Variant)

strDescricao = argDescricao

End Property

Property Get estoqueMinimo() As Variant

estoqueMinimo = dblEstoqueMinimo

End Property

Property Let estoqueMinimo(argEstoqueMinimo As Variant)

dblEstoqueMinimo = argEstoqueMinimo

End Property

Property Get qtdEstoque() As Variant

qtdEstoque = dblQtdEstoque

End Property

Property Let qtdEstoque(argQtdEstoque As Variant)

dblQtdEstoque = argQtdEstoque

End Property

Property Get unidade() As Variant

unidade = strUnidade

End Property

Property Let unidade(argUnidade As Variant)

strUnidade = Ucase(argUnidade)

End Property

Page 58: ACCESS 2010_Classes.pdf

58

Property Get valorUnitario() As Variant

valorUnitario = curValorUnitario

End Property

Property Let valorUnitario(argValorUnitario As Variant)

curValorUnitario = argValorUnitario

End Property

'Método Existe [Com conhecimento de SQL]

'Verifica a existência do objeto Produto na tabela

'correspondente no Banco de Dados.

Function existe(argCodProduto As Variant) As Boolean

On Error GoTo Err_existe

Dim objCon As New aclConexaoBD

Dim rstExiste As Recordset

Dim strSql As String

existe = False

strSql = "Select * " & _

"From Produto " & _

"Where codProduto = " & objCon.valorSql(argCodProduto)

Set rstExiste = objCon.consulta(strSql)

If rstExiste.RecordCount > 0 Then

existe = True

End If

'Fecha o Recordset existe

rstExiste.close

Exit_existe:

Set rstExiste = Nothing

Exit Function

Err_existe:

existe = False

GoTo Exit_existe

End Function

'Método Incluir [Com conhecimento de SQL]

'Inclui um novo objeto na tabela correspondente dentro do Banco de

dados

Function incluir() As Boolean

On Error GoTo Err_incluir

Dim objCon As New aclConexaoBD

Dim strSql As String

strSql = "Insert Into " & _

"Produto(codProduto,descricao,estoqueMinimo,qtdEstoque, _

unidade,valorUnitario) " & _

"Values(" & objCon.valorSql(codProduto) & "," & _

Page 59: ACCESS 2010_Classes.pdf

59

objCon.valorSql(descricao) & "," & _

objCon.valorSql(estoqueMinimo) & "," & _

objCon.valorSql(qtdEstoque) & "," & _

objCon.valorSql(unidade) & "," & _

objCon.valorSql(valorUnitario) & ")"

incluir = (objCon.executa(strSql) > 0)

If incluir Then

'Atualiza os campos de backup

bkpCodProduto = codProduto

End If

Exit_incluir:

Exit Function

Err_incluir:

incluir = False

GoTo Exit_incluir

End Function

'Método Excluir [Com conhecimento de SQL]

'Exclui o objeto atual na tabela correspondente dentro do Banco de

dados

Function excluir() As Boolean

On Error GoTo Err_excluir

Dim objCon As New aclConexaoBD

Dim strSql As String

strSql = "Delete From Produto " & _

"Where codProduto = " & objCon.valorSql(codProduto)

excluir = (objCon.executa(strSql) > 0)

Exit_excluir:

Exit Function

Err_excluir:

excluir = False

GoTo Exit_excluir

End Function

'Método Obter [Com conhecimento de SQL]

'Recupera o objeto Produto através dos argumentos informados

Function obter(argCodProduto As Variant) As Boolean

On Error GoTo Err_obter

Dim objCon As New aclConexaoBD

Dim rstObter As Recordset

Dim strSql As String

strSql = "Select * " & _

"From Produto " & _

"Where codProduto = " & objCon.valorSql(argCodProduto)

Set rstObter = objCon.consulta(strSql)

If rstObter.RecordCount = 0 Then

Page 60: ACCESS 2010_Classes.pdf

60

obter = False

Exit Function

End If

'Atualiza os campos de backup e os identificadores

codProduto = argCodProduto

bkpCodProduto = argCodProduto

'Atualiza os campos restantes

descricao = rstObter.Fields("descricao")

estoqueMinimo = rstObter.Fields("estoqueMinimo")

qtdEstoque = rstObter.Fields("qtdEstoque")

unidade = rstObter.Fields("unidade")

valorUnitario = rstObter.Fields("valorUnitario")

obter = True

'Fecha o Recordset obter

rstObter.close

Exit_obter:

Set rstObter = Nothing

Exit Function

Err_obter:

obter = False

GoTo Exit_obter

End Function

'Método Salvar [Com conhecimento de SQL]

'Salva o objeto atual na tabela correspondente dentro do Banco de

dados

Function salvar() As Boolean

On Error GoTo Err_salvar

Dim objCon As New aclConexaoBD

Dim strSql As String

If existe(bkpCodProduto) Then

strSql = "Update Produto " & _

"Set codProduto = " & objCon.valorSql(codProduto) & _

", descricao = " & objCon.valorSql(descricao) & _

", estoqueMinimo = " & objCon.valorSql(estoqueMinimo)

& _

", qtdEstoque = " & objCon.valorSql(qtdEstoque) & _

", unidade = " & objCon.valorSql(unidade) & _

", valorUnitario = " & objCon.valorSql(valorUnitario)

& _

" Where codProduto = " & objCon.valorSql(bkpCodProduto)

salvar = (objCon.executa(strSql) > 0)

Else

salvar = incluir

End If

If salvar Then

'Atualiza as variáveis de backup com o novo valor da chave

bkpCodProduto = codProduto

End If

Page 61: ACCESS 2010_Classes.pdf

61

Exit_salvar:

Exit Function

Err_salvar:

salvar = False

GoTo Exit_salvar

End Function

'Método baixarEstoque()

'Atualiza o estoque diminuindo a quantidade informada como parâmetro

'e devolve um valor booleano que indica o sucesso da operação;

Function baixarEstoque(argQtd As Double) As Boolean

If dblQtdEstoque - Abs(argQtd) < 0 Then

baixarEstoque = False

Else

dblQtdEstoque = dblQtdEstoque - Abs(argQtd)

baixarEstoque = salvar

End If

End Function

'Método subirEstoque()

'Atualiza o estoque acrescentando a quantidade informada como

'parâmetro e devolve um valor booleano que indica o sucesso

'da operação;

Function subirEstoque(argQtd As Double) As Boolean

dblQtdEstoque = dblQtdEstoque + Abs(argQtd)

subirEstoque = salvar

End Function

'Método estoqueBaixo

'Verifica o estoque atual e compara com o valor de estoque mínimo

'cadastrado para produto e devolve um valor booleano que indica

'se o valor atual está abaixo do previsto.

Function estoqueBaixo() As Boolean

If dblQtdEstoque < dblEstoqueMinimo Then

estoqueBaixo = True

End If

End Function

'Fim da classe...

Pontos Importantes

Desta vez, complementando os itens tratados no artigo anterior, vamos destacar o

pontos a seguir.

1. Controle do estoque: Ao baixarmos o estoque de um produto, devemos verificar se é

possível diminuir a quantidade informada, pois seria impossível retirar mais do que a

quantidade existente em estoque. Além disso, não podemos baixar quantidades

negativas de produto, pois isto significa que estaríamos aumentando a quantidade ao

invés de diminuir. O método somente retornará True se for possível realizar a operação.

Page 62: ACCESS 2010_Classes.pdf

62

Function baixarEstoque(argQtd As Double) As Boolean

If dblQtdEstoque - Abs(argQtd) <= 0 Then

baixarEstoque = False

Else

dblQtdEstoque = dblQtdEstoque - Abs(argQtd)

baixarEstoque = salvar

End If

End Function

2. Conversão de dados no momento da atribuição do valor: Para a atribuição de

algumas propriedades será realizada uma conversão dos dados. No caso da unidade o

valor será convertido em letras maiúsculas para que fique padronizado. Para os atributos

que armazenas a quantidade de produto em estoque e estoque mínimo não serão aceitos

valores negativos, sendo assim todas as quantidades serão convertidas para seus

respectivos valores absolutos.

Property Let estoqueMinimo(argEstoqueMinimo As Variant)

dblEstoqueMinimo = Abs(argEstoqueMinimo)

End Property

Property Let qtdEstoque(argQtdEstoque As Variant)

dblQtdEstoque = Abs(argQtdEstoque)

End Property

Property Let unidade(argUnidade As Variant)

strUnidade = UCase(argUnidade)

End Property

A Interface Gráfica

Assim como no artigo anterior, para que possamos visualizar e manipular os dados dos

produtos devemos criar um formulário com campos para preenchimento e botões de

comando que coordenem as ações sobre os dados.

A seguir serão definidas as características para o formulário no qual iremos trabalhar

com os dados dos objetos relativos aos produtos. Neste caso as especificações de design

também são apenas sugestões, porém as informações de origem de dados, bloqueio de

campos e formatos de dados são obrigatórias, sob pena de não obter a funcionalidade

desejada. Estas especificações estarão marcadas com um asterisco vermelho ao lado.

No formulário teremos uma lista contendo os produtos cadastrados, um campo de texto

para realizar buscas, alguns campos de texto para digitação das informações e os botões

de comando para criar, salvar e excluir registros.

Page 63: ACCESS 2010_Classes.pdf

63

Obs: Somente as propriedades que foram alteradas para um valor diferente do padrão

serão apresentadas. Para as demais utilize o padrão do sistema ou o valor que desejar,

desde que não comprometa a funcionalidade do sistema.

Formulário

Nome: FProduto

Largura: 19cm

Altura: Cabeçalho (1cm) / Detalhe (10cm)

Legenda: Sistema de Vendas

Estilo da borda: fino

Seletores de registro: Não

Botões de navegação: Não

Linhas divisórias: Não

Barras de rolagem: Nenhuma

Caixa de controle: Sim

Botão Fechar: Sim

Botões Min Max: Nenhum

Popup: Sim

Janela Restrita: Não

Controle Listbox

Nome: lstProduto *

Origem da linha: SELECT Produto.codProduto, Produto.descricao,

Produto.unidade, Produto.valorUnitario,

Produto.estoqueMinimo,

Produto.qtdEstoque FROM Produto ORDER BY

Produto.descricao; *

Tipo de Origem da Linha: Tabela/Consulta *

Coluna acoplada: 1 *

Número de colunas: 6 *

Largura das colunas: 0cm;5cm;1cm;2cm;1cm;1cm *

Largura: 10cm

Cor do fundo: Cinza claro

Controles Textbox

Nome: txtPesquisa *

Cor do fundo: Amarelo

Alinhamento: Esquerda

Nome: txtCodigo *

Ativado: Não *

Bloqueado: Sim *

Cor do fundo: Cinza

Alinhamento: Centro

Nome: txtDescricao *

Cor do fundo: Azul claro

Alinhamento: Esquerda

Nome: txtUnidade *

Cor do fundo: Azul claro

Alinhamento: Esquerda

Nome: txtValorUnitario *

Cor do fundo: Azul claro

Alinhamento: Direita

Page 64: ACCESS 2010_Classes.pdf

64

Formato: Unidade Monetária

Nome: txtQtdEstoque *

Cor do fundo: Azul claro

Alinhamento: Centro

Formato: 00

Nome: txtEstoqueMinimo *

Cor do fundo: Cinza

Alinhamento: Centro

Formato: 00

Botões de Comando

Nome: btnNovo *

Legenda: Novo

Cor da Fonte: Azul escuro

Nome: btnSalvar *

Legenda: Salvar

Cor da Fonte: Azul escuro

Nome: btnExcluir *

Legenda: Excluir

Cor da Fonte: Vermelho escuro

Como sugestão de design os campos deverão estar posicionados conforme demonstrado

na figura a seguir, assim como devem ser adicionadas as legendas dos campos, as quais

não foram descritas anteriormente:

Page 65: ACCESS 2010_Classes.pdf

65

Códigos do Formulário

Para que nosso formulário seja capaz de manipular os dados dos objetos produto

deveremos implementar as funcionalidades necessárias que permitam criar um novo

produto, buscar um produto já cadastrado, editar seus dados, salvá-lo ou excluí-lo.

Sendo assim criaremos algumas funções genéricas que sejam úteis para quantos

procedimentos delas necessitem, reaplicando o conceito da reutilização de código. Além

disso incluiremos os códigos dos campos que possuem eventos, além dos botões de

comando.

Todos os códigos a seguir deverão ser colocados no módulo do formulário FProduto.

1. Pesquisa de produtos: Para facilitar a busca de produtos por qualquer parte do nome

utilizaremos um campo de texto cujo valor será o elemento condicional para o código

SQL que será atribuído ao controle lstProduto, atualizando sua propriedade Origem da

Linha após cada alteração realizada no campo de pesquisa. Para isto devemos colocar o

código no evento Ao Alterar do campo txtPesquisa.

Private Sub txtPesquisa_Change()

lstProduto.RowSource = "SELECT codProduto, descricao, " & _

"unidade, valorUnitario, estoqueMinimo, qtdEstoque " & _

"FROM Produto " & _

"WHERE descricao Like '*" & txtPesquisa.Text & "*' " & _

"ORDER BY Produto.descricao;"

lstProduto.Requery

End Sub

2. Limpeza dos campos: Para efetuar a limpeza dos campos de preenchimento

utilizaremos um procedimento genérico cuja função será a de atribuir o valor nulo a

todos os campos de texto e enviar o foco ao campo txtDescricao.

Private Sub limpaCampos()

txtCodigo = Null

txtDescricao = Null

txtUnidade = Null

txtValorUnitario = Null

txtQtdEstoque = Null

txtEstoqueMinimo = Null

txtDescricao.SetFocus

End Sub

3. Novo registro: Para a criação de um novo registro em branco simplesmente iremos

chamar o procedimento limpaCampos() no evento Ao Clicar do botão btnNovo.

Private Sub btnNovo_Click()

Call limpaCampos

End Sub

Page 66: ACCESS 2010_Classes.pdf

66

4. Atualização de campos: Assim como fizemos um procedimento genérico que limpa

os campos para a criação de um novo registro teremos também um que preencha os

campos com as informações de um objeto produto passadas como parâmetro, ou seja, o

procedimento recebe um objeto completo e lança os valores de seus atributos nos

campos do formulário.

Private Sub atualizaCampos(argProduto As clsProduto)

txtCodigo = argProduto.codProduto

txtDescricao = argProduto.descricao

txtUnidade = argProduto.unidade

txtValorUnitario = argProduto.valorUnitario

txtQtdEstoque = argProduto.qtdEstoque

txtEstoqueMinimo = argProduto.estoqueMinimo

End Sub

5. Escolha de produto: Já que teremos também que trabalhar com produtos já

cadastrados, devemos implementar alguma maneira de recuperar suas informações.

Faremos isto utilizando a Listbox lstProduto, que utilizará o procedimento

atualizaCampos() para preencher os campos com as informações do objeto do produto

que foi clicado.

Private Sub lstProduto_Click()

Dim objProduto As New clsProduto

Dim codigoProduto As Long

codigoProduto = lstProduto.Value

If objProduto.obter(codigoProduto) Then

Call atualizaCampos(objProduto)

End If

End Sub

6. Montagem de um objeto: Esta também é uma função genérica que será utilizada por

outros procedimentos ou funções. Seu objetivo é criar um novo objeto produto, coletar

os dados digitados nos campos, atribuir ao objeto criado, e devolvê-lo para quem

chamou a função.

Private Function buscaCampos() As clsProduto

Set buscaCampos = New clsProduto

If IsNull(txtCodigo) Then

txtCodigo = proximoCodigo("codProduto", "Produto")

End If

buscaCampos.codProduto = txtCodigo

buscaCampos.descricao = txtDescricao

buscaCampos.unidade = txtUnidade

buscaCampos.valorUnitario = txtValorUnitario

buscaCampos.qtdEstoque = txtQtdEstoque

buscaCampos.estoqueMinimo = txtEstoqueMinimo

End Function

Page 67: ACCESS 2010_Classes.pdf

67

7. Salvando um produto: Depois de informados os dados de um novo produto, ou

alterados os dados de um produto já cadastrado, necessitaremos de um procedimento

que efetue a gravação destes dados. Para isto o botão btnSalvar conterá o código

necessário no evento Ao Clicar. Ele fará uso da função buscaCampos(), a qual

montará o objeto a ser salvo, e também o método salvar() do objeto, apresentando uma

mensagem ao usuário com o resultado da operação. Após salvar os dados de um produto

também deveremos atualizar a Listbox para que apresente estes dados, sejam eles novos

ou apenas alterados.

Private Sub btnSalvar_Click()

Dim objProduto As clsProduto

If Not IsNull(txtDescricao) And Not IsNull(txtUnidade) And _

Not IsNull(txtValorUnitario) Then

Set objProduto = buscaCampos

If objProduto.salvar Then

MsgBox "O produto foi salvo com sucesso.",vbInformation,"Salvar

produto"

lstProduto.Requery

Call atualizaCampos(objProduto)

Else

MsgBox "Ocorreu um erro durante o salvamento.", vbExclamation, _

"Salvar produto"

End If

Else

MsgBox "Informe os dados do produto.", vbExclamation, "Salvar

produto"

End If

End Sub

8. Excluindo um produto: Além de criar e alterar os dados de um produto, é

importante que também possamos excluí-lo definitivamente de nosso cadastro. Logo

devemos também implementar a funcionalidade para o botão btnExcluir, que conterá o

código necessário também no evento Ao Clicar. Ele também deverá fazer uso da função

buscaCampos() para a montagem do objeto a ser excluído, pois caso contrário a classe

não saberá que objeto deve ser excluído. Em seguida utilizaremos o método excluir() do

objeto, apresentando uma mensagem ao usuário com o resultado da operação. É claro

que após excluir um produto também deveremos atualizar a Listbox para que a mesma

reflita as alterações realizadas.

Private Sub btnExcluir_Click()

Dim objProduto As clsProduto

If Not IsNull(txtCodigo) Then

If MsgBox("Confirma a exclusão do registro?", vbQuestion +

vbYesNo, _

"Excluir produto") = vbYes Then

Set objProduto = buscaCampos

If objProduto.excluir Then

Page 68: ACCESS 2010_Classes.pdf

68

MsgBox "O registro foi excluído com sucesso.", vbInformation,

_

"Excluir produto"

lstProduto.Requery

Call limpaCampos

Else

MsgBox "Ocorreu um erro durante a exclusão.", vbExclamation, _

"Excluir produto"

End If

End If

End If

End Sub

Sistema de Exemplo

Novamente será disponibilizado o link para download do sistema de vendas, já

atualizado com todos os recursos do estado de desenvolvimento em que se encontrar o

projeto.

Mais uma vez recomendo aos desenvolvedores que o consultem apenas para tirar

dúvidas e realizar comparações. Aqueles que realmente quiserem aprender façam toda a

codificação e a montagem das telas manualmente. Somente assim a sua mente irá se

defrontar com as dificuldades do processo e assimilará os passos necessários para a

resolução dos problemas e a conclusão dos objetivos.

Segue o link para download:

Venda00.zip

Caso ainda não esteja com uma tela principal abra o formulário FProduto diretamente

na janela Banco de Dados (Access 2003-) ou no Painel de Navegação (Access 2007+).

Conclusão

Nesta fase não encontramos praticamente nada de novo, mas tivemos a chance de

relembrar a maioria dos procedimentos vistos até o momento. A codificação das

funcionalidades da classe Produto são muito semelhantes à codificação da classe

Cliente. Porém este era o nosso objetivo: relembrar o passo-a-passo necessário para

utilizar objetos em sistemas informatizados no MS-Access/VBA.

Com relação à parte realmente prática da série de artigos estamos chegando na reta

final. No próximo artigo, que será o último em que trabalharemos com a programação

de classes, poderemos perceber um pouco mais da dinâmica de troca de informações

entre os objetos de um sistema. Ao realizarmos vendas de produtos para clientes

estaremos englobando a utilização de todas as nossas classes de uma só vez, trabalhando

com vários objetos instanciados simultaneamente para a conclusão das tarefas.

Com toda certeza você, caro leitor que nos acompanha, já deve estar imaginando os

objetos se interagindo, os métodos realizando tarefas e retornando valores, os atributos

Page 69: ACCESS 2010_Classes.pdf

69

recebendo e fornecendo valores, os objetos sendo enviados inteiramente para métodos

de outros objetos, e assim sucessivamente.

É isto aí, orgulhe-se de dizer: Agora estou quase dominando essa tal de OO!

Page 70: ACCESS 2010_Classes.pdf

70

Classes VII - As Classes Venda e DetalheVenda

Estamos chegando na reta final da criação do sistema de vendas orientado a objetos.

Nesta etapa veremos a codificação das classes Venda e DetalheVenda, além da

implementação de um PDV que será a nossa interface gráfica para realização das

vendas.

No desenrolar da criação dos códigos com certeza você encontrará rotinas repetitivas,

funções não tão necessárias e instâncias em excesso. Além disso, poderá sentir falta de

funcionalidades importantes em um PDV ou mesmo na totalidade do sistema de vendas.

E digo mais, agora que já é praticamente um “expert” em VBA e orientação a objetos

perceberá que um ou outro método poderia ser mais bem implementado de outra

maneira. Mas antes de queimar neurônios tentando entender por que o trabalho está

assim tão “mal projetado”, lembre-se que tudo foi feito com fins didáticos, e a

repetitividade foi proposital, somente para que você fique cansado de tanto manipular

objetos e realmente aprenda como utilizá-los.

Não estaremos totalmente livres do aparecimento de “bugs”, pois apenas nos locais

estritamente necessários foram inseridas rotinas de tratamento de erros. Estes algoritmos

são cansativos de se preparar, então me dei ao luxo de não incluir em todos os

procedimentos, funções e métodos do sistema. Porém nada impede que você, que já

pesquisou o assunto e agora “saca” muito de programação, implemente ao seu bel

prazer, corrigindo erros que porventura se apresentem.

Então chega de papo e mãos à obra...

A Consulta CVenda

Deveremos criar uma consulta que será utilizada por um método da classe Venda. O

nome da consulta será CVenda e seu código SQL será o seguinte:

SELECT Venda.codVenda, Venda.codCliente, Venda.dataVenda,

DetalheVenda.codProduto,

DetalheVenda.qtdProduto, Produto.descricao, Produto.unidade,

Produto.valorUnitario,

(Produto.valorUnitario*DetalheVenda.qtdProduto) AS SubTotal

FROM Venda LEFT JOIN

(Produto RIGHT JOIN DetalheVenda ON

Produto.codProduto=DetalheVenda.codProduto)

ON Venda.codVenda=DetalheVenda.codVenda;

A Classe Venda

O objetivo desta classe, conforme dito anteriormente, é oferecer funcionalidades de

inclusão, consulta, atualização e exclusão dos objetos do tipo venda.

Este é o código da classe, com todos os seus atributos e métodos, que se utilizam de

funções próprias, bem como dos métodos dos objetos da classe ConexaoBD e da classe

Cliente.

Page 71: ACCESS 2010_Classes.pdf

71

Código da classe:

Option Compare Database

Option Explicit

'Atributos da Classe

'Atributo de backup e atributo identificador da Classe

'PK - Código que identifica a venda.

Private bkpCodVenda As Variant

Private lngCodVenda As Variant

'FK - Código que indica o cliente relativo à venda.

Private lngCodCliente As Variant

'Objeto da classe de Descrição de Tipo

Private objetoCliente As New clsCliente

'Data de realização da venda.

Private dtmDataVenda As Variant

'Métodos Get, Set e Let da Classe

Property Get codVenda() As Variant

codVenda = lngCodVenda

End Property

Property Let codVenda(argCodVenda As Variant)

lngCodVenda = argCodVenda

If IsEmpty(bkpCodVenda) Then

bkpCodVenda = lngCodVenda

End If

End Property

Property Get codCliente() As Variant

codCliente = lngCodCliente

End Property

Property Let codCliente(argCodCliente As Variant)

lngCodCliente = argCodCliente

End Property

Property Get dataVenda() As Variant

dataVenda = dtmDataVenda

End Property

Property Let dataVenda(argDataVenda As Variant)

dtmDataVenda = argDataVenda

End Property

Property Get objCliente() As Variant

If Not IsEmpty(codCliente) Then

If objetoCliente.obter(codCliente) Then

Set objCliente = objetoCliente

End If

End If

End Property

'Método Existe [Com conhecimento de SQL]

'Verifica a existência do objeto Venda na tabela

Page 72: ACCESS 2010_Classes.pdf

72

'correspondente no Banco de Dados

Function existe(argCodVenda As Variant) As Boolean

On Error GoTo Err_existe

Dim objCon As New aclConexaoBD

Dim rstExiste As Recordset

Dim strSql As String

existe = False

strSql = "Select * " & _

"From Venda " & _

"Where codVenda = " & objCon.valorSql(argCodVenda)

Set rstExiste = objCon.consulta(strSql)

If rstExiste.RecordCount > 0 Then

existe = True

End If

'Fecha o Recordset existe

rstExiste.close

Exit_existe:

Set rstExiste = Nothing

Exit Function

Err_existe:

existe = False

GoTo Exit_existe

End Function

'Método Incluir [Com conhecimento de SQL]

'Inclui um novo objeto na tabela correspondente

'dentro do Banco de dados

Function incluir() As Boolean

On Error GoTo Err_incluir

Dim objCon As New aclConexaoBD

Dim strSql As String

strSql = "Insert Into " & _

"Venda(codVenda,codCliente,dataVenda) " & _

"Values(" & objCon.valorSql(codVenda) & "," & _

objCon.valorSql(codCliente) & "," & _

objCon.valorSql(dataVenda) & ")"

incluir = (objCon.executa(strSql) > 0)

If incluir Then

'Atualiza os campos de backup

bkpCodVenda = codVenda

End If

Exit_incluir:

Exit Function

Err_incluir:

incluir = False

GoTo Exit_incluir

Page 73: ACCESS 2010_Classes.pdf

73

End Function

'Método Excluir [Com conhecimento de SQL]

'Exclui o objeto atual na tabela correspondente

'dentro do Banco de dados

Function excluir() As Boolean

On Error GoTo Err_excluir

Dim objCon As New aclConexaoBD

Dim strSql As String

strSql = "Delete From Venda " & _

"Where codVenda = " & objCon.valorSql(codVenda)

excluir = (objCon.executa(strSql) > 0)

Exit_excluir:

Exit Function

Err_excluir:

excluir = False

GoTo Exit_excluir

End Function

'Método Obter [Com conhecimento de SQL]

'Recupera o objeto Venda através dos argumentos informados

Function obter(argCodVenda As Variant) As Boolean

On Error GoTo Err_obter

Dim objCon As New aclConexaoBD

Dim rstObter As Recordset

Dim strSql As String

strSql = "Select * " & _

"From Venda " & _

"Where codVenda = " & objCon.valorSql(argCodVenda)

Set rstObter = objCon.consulta(strSql)

If rstObter.RecordCount = 0 Then

obter = False

Exit Function

End If

'Atualiza os campos de backup

'e os identificadores

codVenda = argCodVenda

bkpCodVenda = argCodVenda

'Atualiza os campos restantes

codCliente = rstObter.Fields("codCliente")

dataVenda = rstObter.Fields("dataVenda")

obter = True

'Fecha o Recordset obter

rstObter.close

Exit_obter:

Page 74: ACCESS 2010_Classes.pdf

74

Set rstObter = Nothing

Exit Function

Err_obter:

obter = False

GoTo Exit_obter

End Function

'Método Salvar [Com conhecimento de SQL]

'Salva o objeto atual na tabela correspondente

'dentro do Banco de dados

Function salvar() As Boolean

On Error GoTo Err_salvar

Dim objCon As New aclConexaoBD

Dim strSql As String

If existe(bkpCodVenda) Then

strSql = "Update Venda " & _

"Set codVenda = " & objCon.valorSql(codVenda) & _

", codCliente = " & objCon.valorSql(codCliente) & _

", dataVenda = " & objCon.valorSql(dataVenda) & _

" Where codVenda = " & objCon.valorSql(bkpCodVenda)

salvar = (objCon.executa(strSql) > 0)

Else

salvar = incluir

End If

If salvar Then

'Atualiza as variáveis de backup

'com o novo valor da chave

bkpCodVenda = codVenda

End If

Exit_salvar:

Exit Function

Err_salvar:

salvar = False

GoTo Exit_salvar

End Function

'Método getValorTotal

'Calcula a valor total da venda atual e

'devolve o valor como resultado.

Function getValorTotal() As Currency

getValorTotal = Nz(DSum("SubTotal", "CVenda", _

"codVenda=" & Nz(lngCodVenda, -1)))

End Function

'Fim da classe...

A Classe DetalheVenda

Page 75: ACCESS 2010_Classes.pdf

75

O objetivo desta classe, conforme dito anteriormente, é oferecer funcionalidades de

consulta e atualização dos objetos de ligação entre a venda e os produtos componentes.

Este é o código da classe, com todos os seus atributos e métodos, que se utilizam de

funções próprias, bem como dos métodos dos objetos da classe ConexaoBD e da classe

Produto.

Código da classe:

Option Compare Database

Option Explicit

'Atributos da Classe

'Atributo de backup e atributo identificador da Classe

'PK - FK - Código que indica o produto relacionado.

Private bkpCodProduto As Variant

Private lngCodProduto As Variant

'Atributo de backup e atributo identificador da Classe

'PK - FK - Código que indica a venda relacionada.

Private bkpCodVenda As Variant

Private lngCodVenda As Variant

'Quantidade do poduto relacionado.

Private dblQtdProduto As Variant

'Métodos Get, Set e Let da Classe

Property Get codProduto() As Variant

codProduto = lngCodProduto

End Property

Property Let codProduto(argCodProduto As Variant)

lngCodProduto = argCodProduto

If IsEmpty(bkpCodProduto) Then

bkpCodProduto = lngCodProduto

End If

End Property

Property Get codVenda() As Variant

codVenda = lngCodVenda

End Property

Property Let codVenda(argCodVenda As Variant)

lngCodVenda = argCodVenda

If IsEmpty(bkpCodVenda) Then

bkpCodVenda = lngCodVenda

End If

End Property

Property Get qtdProduto() As Variant

qtdProduto = dblQtdProduto

End Property

Property Let qtdProduto(argQtdProduto As Variant)

dblQtdProduto = argQtdProduto

Page 76: ACCESS 2010_Classes.pdf

76

End Property

'Método Existe [Com conhecimento de SQL]

'Verifica a existência do objeto DetalheVenda na

'tabela correspondente no Banco de Dados

Function existe(argCodProduto As Variant, _

argCodVenda As Variant) As Boolean

On Error GoTo Err_existe

Dim objCon As New aclConexaoBD

Dim rstExiste As Recordset

Dim strSql As String

existe = False

strSql = "Select * " & _

"From DetalheVenda " & _

"Where codProduto = " & objCon.valorSql(argCodProduto) _

And codVenda = " & objCon.valorSql(argCodVenda)"

Set rstExiste = objCon.consulta(strSql)

If rstExiste.RecordCount > 0 Then

existe = True

End If

'Fecha o Recordset existe

rstExiste.close

Exit_existe:

Set rstExiste = Nothing

Exit Function

Err_existe:

existe = False

GoTo Exit_existe

End Function

'Método Incluir [Com conhecimento de SQL]

'Inclui um novo objeto na tabela correspondente

'dentro do Banco de dados

Function incluir() As Boolean

On Error GoTo Err_incluir

Dim objCon As New aclConexaoBD

Dim strSql As String

strSql = "Insert Into " & _

"DetalheVenda(codProduto,codVenda,qtdProduto) " & _

"Values(" & objCon.valorSql(codProduto) & "," & _

objCon.valorSql(codVenda) & "," & _

objCon.valorSql(qtdProduto) & ")"

incluir = (objCon.executa(strSql) > 0)

If incluir Then

'Atualiza os campos de backup

bkpCodProduto = codProduto

bkpCodVenda = codVenda

End If

Page 77: ACCESS 2010_Classes.pdf

77

Exit_incluir:

Exit Function

Err_incluir:

incluir = False

GoTo Exit_incluir

End Function

'Método Excluir [Com conhecimento de SQL]

'Exclui o objeto atual na tabela correspondente

'dentro do Banco de dados

Function excluir() As Boolean

On Error GoTo Err_excluir

Dim objCon As New aclConexaoBD

Dim strSql As String

strSql = "Delete From DetalheVenda " & _

"Where codProduto = " & objCon.valorSql(codProduto) & _

" and codVenda = " & objCon.valorSql(codVenda)

excluir = (objCon.executa(strSql) > 0)

Exit_excluir:

Exit Function

Err_excluir:

excluir = False

GoTo Exit_excluir

End Function

'Método Obter [Com conhecimento de SQL]

'Recupera o objeto DetalheVenda através dos argumentos informados

Function obter(argCodProduto As Variant, _

argCodVenda As Variant) As Boolean

On Error GoTo Err_obter

Dim objCon As New aclConexaoBD

Dim rstObter As Recordset

Dim strSql As String

strSql = "Select * " & _

"From DetalheVenda " & _

"Where codProduto = " & objCon.valorSql(argCodProduto) & _

" And codVenda = " & objCon.valorSql(argCodVenda)

Set rstObter = objCon.consulta(strSql)

If rstObter.RecordCount = 0 Then

obter = False

Exit Function

End If

'Atualiza os campos de backup

'e os identificadores

codProduto = argCodProduto

bkpCodProduto = argCodProduto

codVenda = argCodVenda

Page 78: ACCESS 2010_Classes.pdf

78

bkpCodVenda = argCodVenda

'Atualiza os campos restantes

qtdProduto = rstObter.Fields("qtdProduto")

obter = True

'Fecha o Recordset obter

rstObter.close

Exit_obter:

Set rstObter = Nothing

Exit Function

Err_obter:

obter = False

GoTo Exit_obter

End Function

'Método Salvar [Com conhecimento de SQL]

'Salva o objeto atual na tabela correspondente

'dentro do Banco de dados

Function salvar() As Boolean

On Error GoTo Err_salvar

Dim objCon As New aclConexaoBD

Dim strSql As String

If existe(bkpCodProduto, bkpCodVenda) Then

strSql = "Update DetalheVenda " & _

"Set codProduto = " & objCon.valorSql(codProduto) & _

", codVenda = " & objCon.valorSql(codVenda) & _

", qtdProduto = " & objCon.valorSql(qtdProduto) & _

" Where codProduto = " &

objCon.valorSql(bkpCodProduto) & _

" and codVenda = " & objCon.valorSql(bkpCodVenda)

salvar = (objCon.executa(strSql) > 0)

Else

salvar = incluir

End If

If salvar Then

'Atualiza as variáveis de backup

'com o novo valor da chave

bkpCodProduto = codProduto

bkpCodVenda = codVenda

End If

Exit_salvar:

Exit Function

Err_salvar:

salvar = False

GoTo Exit_salvar

End Function

'Método getSubTotal

'Calcula o subtotal do produto vendido para a

Page 79: ACCESS 2010_Classes.pdf

79

'venda atual e devolve o valor como resultado

Function getSubTotal() As Currency

Dim objProduto As New clsProduto

If Not IsNull(lngCodProduto) And Not IsNull(dblQtdProduto) Then

If objProduto.obter(lngCodProduto) Then

getSubTotal = objProduto.valorUnitario * dblQtdProduto

End If

End If

End Function

'Método getListaProduto(argCodVenda As Long)

'Recebe como parâmetro um código de uma venda e devolve

'um conjunto de registros contendo os códigos dos produtos,

'além de outros dados, relativos à venda informada.

Function getListaProduto(argCodVenda As Long) As Recordset

Dim strSql As String

Dim objCon As New aclConexaoBD

strSql = "SELECT Venda.codVenda, Venda.codCliente,

Venda.dataVenda, " & _

"DetalheVenda.codProduto, DetalheVenda.qtdProduto, " & _

"Produto.descricao, Produto.unidade, Produto.valorUnitario,

" & _

"(Produto.valorUnitario * DetalheVenda.qtdProduto) AS

SubTotal " & _

"FROM Venda LEFT JOIN (Produto RIGHT JOIN DetalheVenda ON "

& _

"Produto.codProduto=DetalheVenda.codProduto) " & _

"ON Venda.codVenda=DetalheVenda.codVenda " & _

"Where Venda.codVenda=" & argCodVenda

Set getListaProduto = objCon.consulta(strSql)

End Function

'Fim da classe...

Mais Funções Auxiliares

Para exibir os itens vendidos na tela, no formato de um cupom fiscal, necessitaremos de

uma função que busque os últimos itens registrados na venda para que possamos

apresentá-los ao usuário.

Assim sendo deveremos incluir mais uma função no módulo Funcoes criado

anteriormente, que será chamada de listaProdutos() e receberá como parâmetros o

código da venda e o número de itens, a partir do último, que devem ser retornados.

Function listaProdutos(argCodVenda As Long, _

Optional ultimos As Integer = 0) As String

Dim rstLista As Recordset

Dim objDetalheVenda As New clsDetalheVenda

Dim contador

Page 80: ACCESS 2010_Classes.pdf

80

Set rstLista = objDetalheVenda.getListaProduto(argCodVenda)

If Not rstLista.EOF Then

rstLista.MoveLast

Else

listaProdutos = ""

Exit Function

End If

While Not rstLista.BOF And (contador < ultimos Or ultimos = 0)

listaProdutos = " " & FormatNumber(rstLista("qtdProduto"),

3) & _

" x " & FormatCurrency(rstLista("valorUnitario")) &

_

" " &

FormatCurrency(rstLista("SubTotal")) & _

vbCrLf & listaProdutos

listaProdutos = Format(rstLista("codProduto"), "000000") & "

" & _

rstLista("unidade") & " " &

rstLista("descricao") & _

vbCrLf & listaProdutos

rstLista.MovePrevious

contador = contador + 1

Wend

End Function

Repare que a função busca os itens começando do final do conjunto de registros,

inclusive montando as linhas também do final para o início, até que seja completada a

quantidade de itens solicitada, ou todos os itens caso a opção não seja informada.

Ponto Importante

Desta vez, relembrando e aprimorando os conceitos da orientação a objetos, vamos

destacar o ponto a seguir.

1. Atributo do tipo objeto: Nos atributos da classe Venda podemos encontrar um que

faz referência à classe Cliente, ou seja, o atributo é um objeto da classe Cliente. Por que

isto? Apenas adiantando um pouco o assunto do próximo artigo criaremos um modelo

de cupom fiscal (bem simples, lógico!!!) no qual esta opção será muito útil. Ao invés de

criarmos uma variável de objeto da classe Cliente e a instanciarmos bastará utilizarmos

o atributo incluído na classe Venda depois que a mesma for obtida através do código da

venda. Neste caso o objeto cliente será instanciado dentro da classe Venda

automaticamente assim que o atributo for referenciado. Com isso será possível também

acessar todos os atributos e métodos do objeto cliente. Veja os trechos de código,

primeiro o método de acesso ao atributo e depois a montagem do cupom fiscal:

Declaração da variável e método de acesso ao atributo:

'Objeto da classe de Descrição de Tipo

Private objetoCliente As New clsCliente

Page 81: ACCESS 2010_Classes.pdf

81

...

Property Get objCliente() As Variant

If Not IsEmpty(codCliente) Then

If objetoCliente.obter(codCliente) Then

Set objCliente = objetoCliente

End If

End If

End Property

...

Montagem do Cupom Fiscal:

cupomVenda = cupomVenda & "CPF: " & objVenda.objCliente.cpf & vbCrLf

cupomVenda = cupomVenda & "Nome: " & objVenda.objCliente.nomeCliente &

vbCrLf

A Interface Gráfica

Desta vez para que possamos visualizar e manipular os dados das vendas resolvi criar

um interessante sistema de PDV para ser a nossa interface gráfica, já que há tanta

curiosidade acerca dos mesmos.

A tela contará com exibição dos itens registrados em formato de cupom, além do

cálculo e registro de produtos utilizando o esquema de digitação do código multiplicado

pela quantidade em um único campo. Também faremos a verificação da descrição do

produto a partir do código e o cálculo de troco a partir do valor pago, além de outras

pequenas funções.

Como não poderia faltar faremos o controle de estoque, tanto baixando itens vendidos

como subindo produtos devolvidos, além de verificação de estoque baixo.

A seguir serão definidas as características para o PDV. Assim como nos anteriores as

especificações de design também são apenas sugestões, porém as informações de

origem de dados, bloqueio de campos e formatos de dados são obrigatórias, sob pena

de, novamente, não obter a funcionalidade desejada. Como de praxe as especificações

estarão marcadas com um asterisco vermelho ao lado.

No formulário teremos um rótulo que exibirá os produtos vendidos, alguns campos de

texto para digitação das informações e os botões de comando para criar e cancelar

vendas, excluir produtos e fechar a tela do PDV.

Obs: Somente as propriedades que foram alteradas para um valor diferente do padrão

serão apresentadas. Para as demais utilize o padrão do sistema, ou o valor que desejar,

desde que não comprometa a funcionalidade do sistema.

Formulário

Nome: FVenda

Largura: 22cm

Altura: Cabeçalho (1,6cm) / Detalhe (15cm)

Page 82: ACCESS 2010_Classes.pdf

82

Cor do fundo: Cabeçalho (Vermelho) / Detalhe (Azul escuro)

Legenda: Sistema de Vendas

Estilo da borda: Fino

Seletores de registro: Não

Botões de navegação: Não

Linhas divisórias: Não

Barras de rolagem: Nenhuma

Caixa de controle: Não

Botão Fechar: Não

Botões Min Max: Nenhum

Popup: Sim

Janela Restrita: Não

Controle Label

Nome: lblProdutos *

Largura: 9,7cm *

Altura: 10,4cm *

Controles Textbox

Nome: txtCodigoVenda *

Formato: 000000

Ativado: Não *

Bloqueado: Sim *

Cor do fundo: Cinza

Alinhamento: Centro

Nome: txtData *

Formato: dd/mm/yyyy *

Cor do fundo: Branco

Máscara de entrada: 00/00/00;;_

Alinhamento: Centro

Nome: txtCodCliente *

Formato: 000

Cor do fundo: Branco

Alinhamento: Centro

Nome: txtNomeCliente *

Cor do fundo: Cinza

Alinhamento: Esquerda

Ativado: Não *

Bloqueado: Sim *

Nome: txtProdutoQtd *

Cor do fundo: Amarelo

Alinhamento: Esquerda

Tamanho da Fonte: 28

Nome: txtDescricao *

Cor do fundo: Cinza

Alinhamento: Esquerda

Tamanho da Fonte: 14

Ativado: Não *

Bloqueado: Sim *

Nome: txtUnidade *

Cor do fundo: Cinza

Alinhamento: Centro

Page 83: ACCESS 2010_Classes.pdf

83

Tamanho da Fonte: 14

Ativado: Não *

Bloqueado: Sim *

Nome: txtQtd *

Cor do fundo: Cinza

Formato: Padrão

Casas decimais: 3

Alinhamento: Centro

Tamanho da Fonte: 14

Ativado: Não *

Bloqueado: Sim *

Nome: txtValorUnt *

Cor do fundo: Cinza

Formato: Unidade Monetária

Alinhamento: Direita

Tamanho da Fonte: 14

Ativado: Não *

Bloqueado: Sim *

Nome: txtSubTotal *

Cor do fundo: Cinza

Formato: Unidade Monetária

Alinhamento: Direita

Tamanho da Fonte: 14

Ativado: Não *

Bloqueado: Sim *

Nome: txtTotal *

Cor do fundo: Laranja

Formato: Unidade Monetária

Alinhamento: Direita

Tamanho da Fonte: 24

Ativado: Não *

Bloqueado: Sim *

Nome: txtPago *

Cor do fundo: Cinza

Formato: Unidade Monetária

Alinhamento: Direita

Tamanho da Fonte: 16

Nome: txtTroco *

Cor do fundo: Cinza

Formato: Unidade Monetária

Alinhamento: Direita

Tamanho da Fonte: 16

Ativado: Não *

Bloqueado: Sim *

Botões de Comando

Nome: btnExcluirProduto *

Legenda: Excluir Produto

Cor da Fonte: Vermelho escuro

Nome: btnCancelar *

Legenda: Cancelar Venda

Cor da Fonte: Vermelho escuro

Page 84: ACCESS 2010_Classes.pdf

84

Nome: btnNovo *

Legenda: Nova Venda

Cor da Fonte: Azul escuro

Nome: btnFechar *

Legenda: Fechar

Cor da Fonte: Vermelho escuro

Como sugestão de design os campos deverão estar posicionados conforme demonstrado

na figura a seguir, assim como devem ser adicionadas as legendas dos campos, as quais

não foram descritas anteriormente:

Códigos do Formulário

Para que nosso formulário seja capaz de manipular os dados dos objetos produto

deveremos implementar as funcionalidades necessárias que permitam criar uma nova

venda, calcular os valores dos produtos vendidos, registrar as vendas, controlar estoque,

devolver produtos e cancelar a venda.

Sendo assim criaremos algumas funções genéricas que sejam úteis para quantos

procedimentos delas necessitem, reaplicando o conceito da reutilização de código. Além

disso, incluiremos os códigos dos campos que possuem eventos, assim como dos botões

de comando.

Todos os códigos a seguir deverão ser colocados no módulo do formulário FVenda.

Page 85: ACCESS 2010_Classes.pdf

85

1. Limpeza dos campos: Para efetuar a limpeza dos campos de preenchimento

utilizaremos dois procedimentos genérico cuja função será a de atribuir o valor nulo a

todos os campos de texto, deixar o rótulo de exibição do cupom em branco e enviar o

foco ao campo txtProdutoQtd. Repare que um procedimento reutiliza o código do

outro, já que os dois são independentes e o primeiro é utilizado apenas na descrição do

produto e o segundo limpa todos os campos da tela.

Private Sub limpaExibicaoProduto()

txtDescricao = Null

txtUnidade = Null

txtQtd = Null

txtValorUnt = Null

txtSubtotal = Null

End Sub

Private Sub limpaCampos()

txtCodigoVenda = Null

txtData = Null

txtCodCliente = Null

txtNomeCliente = Null

txtProdutoQtd = Null

txtTotal = Null

txtPago = Null

txtTroco = Null

Call limpaExibicaoProduto

lblProdutos.Caption = ""

txtProdutoQtd.SetFocus

End Sub

2. Nova venda: Para a criação de uma nova venda em branco simplesmente iremos

chamar o procedimento limpaCampos() no evento Ao Clicar do botão btnNovo.

Private Sub btnNovo_Click()

Call limpaCampos

End Sub

3. Cálculo do troco: Com a finalidade de informar o valor do troco a partir do valor da

venda e do valor pago utilizaremos um procedimento que será acionado no evento Após

Atualizar do campo txtPago.

Private Sub txtPago_AfterUpdate()

If Not IsNull(txtPago) Then

txtTroco = CDbl(txtPago) - CDbl(Nz(txtTotal))

Else

txtTroco = Null

End If

End Sub

4. Exibição da lista de produtos registrados: Para exibir a lista de produtos

registrados sempre que for incluído ou retirado algum produto utilizaremos um

procedimento genérico cuja função será a de buscar o lista utilizando a função

listaProdutos(), atualizar a exibição do valor total da venda no campo txtTotal e

acionar o procedimento que calcula e exibe o valor do troco.

Sub atualizaLista()

Page 86: ACCESS 2010_Classes.pdf

86

Dim objVenda As New clsVenda

If Not IsNull(txtCodigoVenda) Then

If objVenda.obter(txtCodigoVenda) Then

lblProdutos.Caption = listaProdutos(Nz(txtCodigoVenda, -1), 10)

txtTotal = objVenda.getValorTotal

Call txtPago_AfterUpdate

End If

End If

End Sub

5. Carregamento do formulário: No evento Ao Carregar do formulário

implementaremos uma pequena rotina que simplesmente atualizará a lista de produtos e

moverá o foco para o campo txtProdutoQtd. A atualização da lista só fará sentido

quando abrirmos novamente um formulário já carregado anteriormente (por exemplo,

quando abrimos o formulário, mudamos para o modo Design e voltamos para o modo

Formulário).

Private Sub Form_Load()

Call atualizaLista

txtProdutoQtd.SetFocus

End Sub

6. Criação da venda: Ao iniciarmos uma venda deveremos gerar o código da mesma.

Assim criaremos um procedimento genérico que lança mão da função

proximoCodigo() para gerar o código da venda, além de atribuir a data atual caso o

usuário não tenha informado alguma data específica.

Sub preencheVenda()

If IsNull(txtCodigoVenda) Then

txtCodigoVenda = proximoCodigo("codVenda", "Venda")

End If

If IsNull(txtData) Then

txtData = Date

End If

End Sub

7. Busca do cliente: Para que seja exibido o nome do cliente assim que o código for

informado utilizaremos esta rotina no evento Após Atualizar do campo txtCodCliente.

Assim será preenchido o campo txtNomeCliente a partir dos dados retornados pelo

objeto cliente, ou então um aviso ao usuário informando que o código do cliente é

inválido. Ao ser informado um cliente válido a venda também será gerada através de

uma chamada ao procedimento preencheVenda().

Private Sub txtCodCliente_AfterUpdate()

Dim objCliente As New clsCliente

If Not IsNull(txtCodCliente) Then

If objCliente.obter(CLng(txtCodCliente)) Then

Call preencheVenda

txtNomeCliente = objCliente.nomeCliente

Page 87: ACCESS 2010_Classes.pdf

87

Else

txtNomeCliente = Null

txtCodCliente = Null

MsgBox "Código do cliente inválido!", _

vbExclamation, "Erro!"

End If

End If

End Sub

8. Busca do produto em tempo real: O procedimento a seguir permitirá que seja

exibida a descrição e a unidade do produto no exato momento em que o código for

digitado. Ele será incluído no evento Ao Alterar do campo txtProdutoQtd. Caso o

código não corresponda a nenhum produto será exibida uma mensagem no campo

txtDescricao informando que o código não está cadastrado. Veja que ele somente será

executado completamente caso o valor digitado possa ser interpretado como valor

numérico, ou seja, um valor compatível com o código do produto.

Private Sub txtProdutoQtd_Change()

Dim objProduto As New clsProduto

If txtProdutoQtd.Text <> "" Then

If InStr(txtProdutoQtd.Text, "*") = 0 Then

If IsNumeric(txtProdutoQtd.Text) Then

If objProduto.obter(CLng(txtProdutoQtd.Text)) Then

txtDescricao = objProduto.descricao

txtUnidade = objProduto.unidade

Else

txtDescricao = "Código não cadastrado..."

txtUnidade = Null

End If

txtQtd = Null

txtValorUnt = Null

txtSubtotal = Null

End If

End If

Else

txtDescricao = Null

txtUnidade = Null

End If

End Sub

9. Exibição de produto: Para exibirmos todos os dados do produto a ser registrado em

uma venda criaremos um procedimento genérico que recebe como argumento um objeto

detalhe de venda cujas propriedades e métodos fornecerão as informações para o

preenchimento dos campos. Repare que o valor do subtotal é calculado pelo método

getSubTotal() do objeto.

Sub exibeProduto(argDetalhe As clsDetalheVenda)

Dim objProduto As New clsProduto

If objProduto.obter(argDetalhe.codProduto) Then

txtDescricao = objProduto.descricao

txtUnidade = objProduto.unidade

txtQtd = argDetalhe.qtdProduto

Page 88: ACCESS 2010_Classes.pdf

88

txtValorUnt = objProduto.valorUnitario

txtSubtotal = argDetalhe.getSubTotal

End If

End Sub

10. Registro do produto: Cada produto constante da venda deverá ser registrado antes

do fechamento da venda. Para isto deveremos realizar várias verificações, utilizando

vários objetos neste procedimento que será incluído no evento Antes de Atualizar do

campo txtProdutoQtd para que seja capaz de cancelar o registro caso alguma

informação não esteja correta. Primeiro será verificada a validade do código do produto

e a correta informação da quantidade, caso seja incluída, atribuindo uma unidade em

caso contrário. Em seguida será checada a validade do código da venda e também da

data, além do código do cliente, caso seja informado (uma venda sem cliente será

considerada venda ao consumidor). Para não ocorrerem conflitos o código da venda

será sempre gerado automaticamente, não sendo permitida sua alteração posterior. O

próximo passo será verificar se a quantidade solicitada existe em estoque. Caso não

possa ser atendida integralmente o registro é cancelado. Existindo a quantidade o

produto é registrado, assim como qualquer alteração nos dados da venda. Por último a

exibição dos dados é atualizada e o estoque atualizado, informando o usuário se o

estoque ficar abaixo do mínimo. Caso ocorram erros durante o processo o esquema de

tratamento de erros avisa o usuário sobre qual passo gerou o problema.

Private Sub txtProdutoQtd_BeforeUpdate(Cancel As Integer)

On Error GoTo Err_txtProdutoQtd_AfterUpdate

Dim codigoProduto As Long

Dim qtdProduto As Double

Dim posicao As Integer

Dim status As Integer

Dim objVenda As New clsVenda

Dim objDetalhe As New clsDetalheVenda

Dim objProduto As New clsProduto

status = 0

If Not IsNull(txtProdutoQtd) Then

Call preencheVenda

posicao = InStr(txtProdutoQtd, "*")

If posicao > 0 Then

status = 1

codigoProduto = CLng(Left(txtProdutoQtd, posicao - 1))

status = 2

qtdProduto = CDbl(Right(txtProdutoQtd, Len(txtProdutoQtd) -

posicao))

Else

status = 3

codigoProduto = CLng(txtProdutoQtd)

qtdProduto = 1

End If

status = 4

objVenda.codVenda = CLng(txtCodigoVenda)

status = 5

Page 89: ACCESS 2010_Classes.pdf

89

objVenda.dataVenda = CDate(txtData)

status = 6

If Not IsNull(txtCodCliente) Then

objVenda.codCliente = CLng(txtCodCliente)

End If

If objProduto.obter(codigoProduto) Then

If objProduto.qtdEstoque < qtdProduto Then

MsgBox "O estoque existente não é suficiente!" & vbCrLf & vbLf

& _

"Estoque atual: " & FormatNumber(objProduto.qtdEstoque,

3) & _

" " & objProduto.unidade, _

vbExclamation, "Estoque Baixo"

Cancel = True

Exit Sub

End If

End If

status = 7

If objVenda.salvar Then

objDetalhe.codVenda = objVenda.codVenda

objDetalhe.codProduto = codigoProduto

objDetalhe.qtdProduto = qtdProduto

status = 8

If objDetalhe.salvar Then

Call exibeProduto(objDetalhe)

Call atualizaLista

If objProduto.obter(codigoProduto) Then

status = 9

If objProduto.baixarEstoque(qtdProduto) Then

If objProduto.estoqueBaixo Then

MsgBox "O estoque ficou abaixo da quantidade mínima!" &

_

vbCrLf & vbLf & _

"Estoque atual: " &

FormatNumber(objProduto.qtdEstoque, 3) & _

" " & objProduto.unidade, vbExclamation, "Estoque

Baixo"

End If

Else

MsgBox "Ocorreu um erro na atualização do estoque.", _

vbExclamation, "Erro!"

End If

End If

Else

MsgBox "Ocorreu um erro ao incluir o produto.", _

vbExclamation, "Erro!"

Cancel = True

End If

Else

MsgBox "Ocorreu um erro ao incluir a venda.", _

vbExclamation, "Erro!"

Cancel = True

End If

End If

Exit_txtProdutoQtd_AfterUpdate:

Page 90: ACCESS 2010_Classes.pdf

90

Exit Sub

Err_txtProdutoQtd_AfterUpdate:

Select Case status

Case 1, 3

MsgBox "Código do produto inválido!", vbExclamation, "Erro!"

Case 2

MsgBox "Quantidade do produto inválida!", vbExclamation, "Erro!"

Case 5

MsgBox "Data inválida!", vbExclamation, "Erro!"

Case 6

MsgBox "Código do cliente inválido!", vbExclamation, "Erro!"

Case 7

MsgBox "Ocorreu um erro ao incluir a venda!", vbExclamation,

"Erro!"

Case 8

MsgBox "Ocorreu um erro ao incluir o produto!", vbExclamation,

"Erro!"

Case 9

MsgBox "Ocorreu um erro ao atualizar o estoque!", vbExclamation,

"Erro!"

Case Else

MsgBox "Ocorreu um erro. O sistema informou a seguinte

mensagem:" & _

vbCrLf & vbLf & Err.Description, vbExclamation, "Erro!"

End Select

Cancel = True

Resume Exit_txtProdutoQtd_AfterUpdate

End Sub

Obs: Apenas para esclarecimento sobre o tratamento de erros lembre-se que este não é

um sistema real. Sendo assim os códigos foram colocados de qualquer maneira para

atingir o objetivo do curso: aprender a utilizar os objetos. Da maneira que foram

implementados os registros um erro no meio do processo impediria que o final do

registro de uma venda ou de um produto ocorresse, deixando os dados corrompidos.

Em um sistema real deveriam ser utilizadas transações para garantir que todos os

processos ocorressem integralmente, do início ao fim, ou então que todas as etapas

fossem canceladas e os dados retornassem ao estado original. Não poderíamos, por

exemplo, ter uma venda registrada sem que o estoque fosse atualizado. Mas isto é outra

história...

11. Atualização das informações: Após o registro de um produto as informações

exibidas devem ser atualizadas e o foco retornar para o campo de digitação de produto e

quantidade, a fim de que ele esteja pronto para efetuar novo registro. Para executar esta

tarefa criaremos um procedimento no evento Após Atualizar do campo

txtProdutoQtd.

Private Sub txtProdutoQtd_AfterUpdate()

btnNovo.SetFocus

txtProdutoQtd.SetFocus

txtProdutoQtd = Null

Call preencheVenda

Call atualizaLista

End Sub

Page 91: ACCESS 2010_Classes.pdf

91

12. Exclusão de produto da venda: Caso tenhamos que excluir um único produto da

venda, antes que ela seja fechada, deveremos desfazer os passos executados no registro

do mesmo. Para isto devemos criar um procedimento no evento Ao Clicar do botão

btnExcluirProduto. Ele será encarregado de solicitar ao usuário o código do produto

que deverá ser excluído, checando sua validade, atualizando o estoque e finalmente

excluindo o produto, sendo que os dados de exibição devem ser novamente atualizados

através de uma chamada ao procedimento genérico atualizaLista(). Repare que não

excluiremos o produto em si, mas apenas o seu registro na venda.

Private Sub btnExcluirProduto_Click()

Dim objDetalheVenda As New clsDetalheVenda

Dim objProduto As New clsProduto

Dim codigoProduto As String

If Not IsNull(txtCodigoVenda) Then

codigoProduto = InputBox("Informe o código do produto a ser

excluído:", _

"Exclusão de Produto")

Else

Exit Sub

End If

If codigoProduto <> "" Then

If IsNumeric(codigoProduto) Then

If objDetalheVenda.obter(CLng(codigoProduto),

CLng(txtCodigoVenda)) Then

If objProduto.obter(CLng(codigoProduto)) Then

If objProduto.subirEstoque(objDetalheVenda.qtdProduto) Then

If objDetalheVenda.excluir Then

MsgBox "O produto foi excluído com sucesso!", _

vbInformation, "Exclusão de Produto"

Call atualizaLista

Else

MsgBox "Ocorreu um erro durante a exclusão do produto!",

_

vbExclamation, "Exclusão de Produto"

End If

End If

End If

End If

Else

MsgBox "Código de produto inválido!", _

vbExclamation, "Exclusão de Produto"

End If

End If

End Sub

Obs: Veja que não incluí tratamento de erro neste procedimento. Também não incluí e

nem incluirei em vários outros. Esta tarefa deverá ser executada no evento Ao Praticar

do objeto LeitorAplicado.

13. Cancelamento da venda: Assim como podemos excluir um produto registrado

também podemos cancelar uma venda inteira. Para executar esta tarefa deveremos

desfazer todos os passos executados para registrar todos os produtos até o momento. O

procedimento responsável será incluído no evento Ao Clicar do botão btnCancelar. O

Page 92: ACCESS 2010_Classes.pdf

92

cancelamento deverá contemplar a busca do conjunto de registros dos produtos da

venda, através do método getListaProduto() do objeto detalhe de venda, que serão

verificados um a um para retorno ao estoque. Em seguida a venda será excluída,

ocasionando a exclusão dos registros associados na tabela DetalheVenda pelo

mecanismo do relacionamento em cascata. Após a exclusão os campos serão limpos

para iniciar nova venda.

Private Sub btnCancelar_Click()

Dim objVenda As New clsVenda

Dim objDetalheVenda As New clsDetalheVenda

Dim objProduto As New clsProduto

Dim rstLista As Recordset

If objVenda.obter(Nz(txtCodigoVenda, -1)) Then

If MsgBox("Confirma o cancelamento da venda?", _

vbQuestion + vbYesNo, "Cancelar Venda") = vbYes Then

Set rstLista = objDetalheVenda.getListaProduto(txtCodigoVenda)

While Not rstLista.EOF

Call objProduto.obter(rstLista("codProduto"))

Call objProduto.subirEstoque(rstLista("qtdProduto"))

rstLista.MoveNext

Wend

If objVenda.excluir Then

MsgBox "A venda foi cancelada com sucesso.", _

vbInformation, "Cancelar Venda"

Call limpaCampos

Else

MsgBox "Ocorreu um erro durante o cancelamento.", _

vbExclamation, "Cancelar Venda"

End If

End If

End If

End Sub

14. Fechamento do PDV: Para encerrarmos as atividades no PDV simplesmente

iremos incluir um procedimento que fecha o formulário no evento Ao Clicar do botão

btnFechar.

Private Sub btnFechar_Click()

DoCmd.close

End Sub

Sistema de Exemplo

Novamente será disponibilizado o link para download do sistema de vendas, já

atualizado com todos os recursos do estado de desenvolvimento em que se encontrar o

projeto.

Page 93: ACCESS 2010_Classes.pdf

93

Continua a recomendação de consultar o exemplo apenas para tirar dúvidas e verificar

como foi feito, além de ver o sistema em funcionamento. Treinem bastante, digitem,

testem, façam o cérebro pedir água. Esta é a única maneira de realmente assimilar o

conhecimento.

Segue o link para download:

Venda00.zip

Caso ainda não esteja com uma tela principal abra o formulário FVenda diretamente na

janela Banco de Dados (Access 2003-) ou no Painel de Navegação (Access 2007+).

Conclusão

Depois desta exaustiva etapa foi possível percebermos o quanto os objetos devem

interagir para chegar ao fim de uma tarefa. Funções, procedimentos, eventos, métodos e

atributos trabalham em conjunto para produzir resultados que atendam as necessidades

do usuário.

Este artigo foi dedicado a demonstrar de maneira maçante a criação, utilização e troca

de informações entre objetos em meio aos códigos do restante do sistema, por isso

mesmo foi bem mais longo que os demais.

Além de toda a programação em si foi possível trabalharmos apresentando um sistema

interessante, útil e muito comum no dia a dia, do qual muitos tinham a curiosidade de

conhecer e compreender a forma de implementação: o PDV. Mas nosso sistema de

vendas ultramoderno, com tecnologia orientada a objetos, não estaria completo sem ele,

não é mesmo?

Aqui praticamente encerramos a parte mais trabalhosa. De agora em diante veremos

apenas a finalização do sistema, algo mais estético do que funcional, além de um pouco

mais teoria nos artigos seguintes, com a apresentação do Genesis, a ferramenta case

para VBA que facilitará a sua vida, e a abordagem sobre utilização de objetos no MS-

Access para aprimorar seus projetos.

Page 94: ACCESS 2010_Classes.pdf

94

Classes VIII - Finalização do Sistema

Eis que chegamos à última etapa da criação do nosso sistema de vendas orientado a

objetos.

Finalmente teremos o sistema totalmente pronto e funcional para que seja possível

visualizar a aplicação de todos os conceitos aprendidos nesta jornada de busca do

conhecimento.

A finalização do aplicativo não trará exatamente alguma novidade, mas apenas o

fechamento do projeto, ao criarmos a interface gráfica de gerenciamento principal do

software e os relatórios para exibição dos dados. A exceção será para a apresentação do

cupom de venda, que será um exemplo bastante simplificado de um cupom fiscal de

verdade, utilizado em sistemas comerciais.

A Última Função Auxiliar

Para montar o cupom de venda, no formato de um cupom fiscal, necessitaremos de uma

função que busque a lista de produtos e acrescente os dados da empresa ou do sistema,

além dos dados do cliente, caso haja algum específico.

Assim sendo deveremos incluir mais uma função no módulo Funcoes criado

anteriormente, que será chamada de cupomVenda(), a qual utilizará a função

listaProdutos() criada anteriormente. A função cupomVenda() receberá como

parâmetro o código da venda para a qual o cupom deve ser retornado.

Este será o código da função:

Function cupomVenda(argCodVenda As Long) As String

Dim objVenda As New clsVenda

If Not objVenda.obter(argCodVenda) Then

cupomVenda = ""

Exit Function

End If

cupomVenda = "VENDA OO" & vbCrLf

cupomVenda = cupomVenda & "Sistema de Venda Orientado a Objetos" & vbCrLf

cupomVenda = cupomVenda & "Av. do Passa 4 nr 171, Centro" & vbCrLf

cupomVenda = cupomVenda & "Objetolândia - OB" & vbCrLf

cupomVenda = cupomVenda & "Fone: (0xx62) 3322-4455" & vbCrLf

cupomVenda = cupomVenda & "++++++++++++++++++++++++++++++++++++++++" &

vbCrLf

cupomVenda = cupomVenda & Format(objVenda.dataVenda, "dd/mm/yy") & _

" Venda: " & _

Format(objVenda.codVenda, "000000") & vbCrLf

cupomVenda = cupomVenda & vbCrLf

cupomVenda = cupomVenda & " CUPOM FISCAL" & vbCrLf

cupomVenda = cupomVenda & vbCrLf

cupomVenda = cupomVenda & listaProdutos(argCodVenda)

cupomVenda = cupomVenda & "++++++++++++++++++++++++++++++++++++++++" &

vbCrLf

Page 95: ACCESS 2010_Classes.pdf

95

cupomVenda = cupomVenda & vbCrLf

cupomVenda = cupomVenda & "TOTAL " &

_

FormatCurrency(objVenda.getValorTotal) & vbCrLf

cupomVenda = cupomVenda & vbCrLf

If Not IsNull(objVenda.codCliente) Then

cupomVenda = cupomVenda & "Cliente: " &

Format(objVenda.objCliente.codCliente, _

"0000") & vbCrLf

cupomVenda = cupomVenda & "CPF: " & objVenda.objCliente.cpf & vbCrLf

cupomVenda = cupomVenda & "Nome: " & objVenda.objCliente.nomeCliente &

vbCrLf

Else

cupomVenda = cupomVenda & "Venda ao consumidor" & vbCrLf

End If

cupomVenda = cupomVenda & vbCrLf

cupomVenda = cupomVenda & "Obrigado e volte Sempre..."

End Function

Veja que no caso de não haver um cliente registrado para a venda ela será exibida como

Venda ao consumidor, já que nem sempre em uma venda é necessário identificar o

cliente.

Pronto. Agora, a partir de qualquer local do nosso projeto, poderemos buscar um cupom

de venda apenas utilizando a função e passando o código da venda como parâmetro.

O Formulário Principal

O formulário principal é o que se abre automaticamente assim que o aplicativo é

iniciado e será o responsável por permitir acesso aos demais itens do sistema.

A seguir serão definidas as características para o formulário principal. Assim como nos

anteriores as especificações de design também são apenas sugestões, porém as

informações de origem de dados, bloqueio de campos e formatos de dados são

obrigatórias, sob pena de, novamente, não obter a funcionalidade desejada. Como de

praxe as especificações estarão marcadas com um asterisco vermelho ao lado.

No formulário teremos apenas os rótulos como o nome e a descrição do sistema, além

de mais seis botões de comando para acesso aos formulários de cadastro, PDV e

relatórios, com seus respectivos rótulos.

Formulário

Nome: FPrincipal

Altura: Cabeçalho (4cm) / Detalhe (11cm)

Cor do fundo: Cabeçalho (Azul) / Detalhe (Cinza claro)

Legenda: Sistema de Vendas

Seletores de registro: Não

Botões de navegação: Não

Linhas divisórias: Não

Barras de rolagem: Nenhuma

Caixa de controle: Sim

Botão Fechar: Sim

Botões Min Max: Nenhum

Page 96: ACCESS 2010_Classes.pdf

96

Queremos que nosso formulário seja exibido automaticamente assim que o Sistema de

Vendas for aberto. Também não queremos que o painel de navegação (ou a Janela

Banco de Dados) seja exibido. Para isso vamos realizar o seguinte procedimento:

No Access 2003 ou inferior: Vá ao menu Ferramentas -> Inicializar. Em seguida, na

caixa de texto Exibir Formulário/Página informe o nome do formulário FPrincipal.

Desmarque a opção Exibir Janela Banco de Dados e clique em Ok.

No Access 2007: Vá ao Botão do Office, no canto superior esquerdo da tela, depois em

Opções do Access -> Banco de Dados Atual. Em seguida, na caixa de texto Exibir

Formulário informe o nome do formulário FPrincipal. Desmarque também a opção

Exibir Painel de Navegação e clique em Ok.

No Access 2010: Vá ao menu Arquivo, depois em Opções -> Banco de Dados Atual.

Em seguida, na caixa de texto Exibir Formulário informe o nome do formulário

FPrincipal.

Botões de Comando

Nome: btnCliente *

Nome: btnProduto *

Nome: btnPDV *

Nome: btnListaCliente *

Nome: btnListaProduto *

Nome: btnRelVenda *

Como sugestão de design os campos deverão estar posicionados conforme demonstrado

na figura a seguir, assim como devem ser adicionadas as legendas dos botões, as quais

não foram descritas anteriormente:

Page 97: ACCESS 2010_Classes.pdf

97

Códigos do Formulário

Para que nosso formulário seja capaz de permitir o acesso aos itens do sistema

deveremos programar as funcionalidades necessárias que permitam abrir os formulários

e relatórios existentes.

Por ser um processo bastante simples e repetitivo não detalharei cada um dos comandos.

Colocarei os comandos agrupados pelo seu tipo de funcionalidade.

Todos os códigos a seguir deverão ser colocados no módulo do formulário FPrincipal.

1. Abertura dos formulários de cadastro: Para abrirmos os formulários de cadastro e

o PDV utilizaremos o evento Ao Clicar dos botões com o comando OpenForm.

Private Sub btnCliente_Click()

DoCmd.OpenForm "FCliente"

End Sub

Private Sub btnPDV_Click()

DoCmd.OpenForm "FVenda"

End Sub

Private Sub btnProduto_Click()

DoCmd.OpenForm "FProduto"

End Sub

2. Abertura dos relatórios: Para abrirmos os relatórios utilizaremos o evento Ao

Clicar dos botões com o comando OpenReport.

Page 98: ACCESS 2010_Classes.pdf

98

Private Sub btnListaCliente_Click()

DoCmd.OpenReport "RCliente", acViewPreview

End Sub

Private Sub btnListaProduto_Click()

DoCmd.OpenReport "RProduto", acViewPreview

End Sub

Private Sub btnRelVenda_Click()

DoCmd.OpenReport "RVenda", acViewPreview

End Sub

3. Maximização do formulário: Para que o formulário principal se mantenha

maximizado o tempo todo utilizaremos o comando Maximize nos eventos Ao Abrir e

Ao Ativar do mesmo.

Private Sub Form_Activate()

DoCmd.Maximize

End Sub

Private Sub Form_Open(Cancel As Integer)

DoCmd.Maximize

End Sub

Relatórios

Os dados cadastrados e as vendas registradas poderão ser exibidos e preparados para

impressão através dos relatórios que criaremos.

Como não é o objetivo deste curso não detalharemos a criação dos relatórios, sendo que

apenas descreveremos a função de cada um deles. Os relatórios Lista de Clientes e

Lista de Produtos devem ser gerados de maneira simples a partir das tabelas Cliente e

Produto, respectivamente. O Relatório de Vendas deve ser gerado a partir da consulta

CVenda. Já o cupom fiscal será um pouco mais detalhado, já que utiliza um controle

não acoplado com a função cupomVenda().

Lista de Clientes

Responsável por exibir os dados dos clientes cadastrados em ordem alfabética de

nomes. O nome dele será RCliente.

Lista de Produtos

Responsável por exibir os dados dos produtos cadastrados em ordem alfabética de

descrição. O nome dele será RProduto.

Page 99: ACCESS 2010_Classes.pdf

99

Relatório de Vendas

Responsável por exibir os dados das vendas registradas, o nome dos clientes e os

produtos componentes de cada venda. O nome dele será RVenda.

Cupom de Venda

O cupom de venda exibirá os dados da venda em formato de um cupom fiscal

simplificado. O nome dele será RCupom.

Ao invés do formulário principal ele será acionado a partir do PDV, ao clicarmos duas

vezes no controle lblProdutos, o mesmo que exibe os produtos registrados no momento

da venda no PDV. Para isto incluiremos o código abaixo no evento Ao Clicar Duas

Vezes no controle lblProdutos do formulário FVenda.

Private Sub lblProdutos_DblClick(Cancel As Integer)

If Not IsNull(txtCodigoVenda) Then

DoCmd.OpenReport "RCupom", acViewPreview, , , , txtCodigoVenda

End If

End Sub

Page 100: ACCESS 2010_Classes.pdf

100

Repare que o código da venda, que será o parâmetro para a função cupomVenda(), será

passado através do argumento OpenArgs de abertura do relatório. Ao abrir o formulário

o código estará disponível para a função através da propriedade AbrirArgs do relatório.

Para montarmos o relatório com o cupom criaremos apenas um controle caixa de texto

não acoplado com o seguinte código:

=cupomVenda(Nz([AbrirArgs]))

A função buscará todas as informações sobre a venda e seus produtos e retornará para o

controle, que as exibirá no relatório.

O controle terá o nome de txtCupom, a propriedade Pode Ampliar definida como Sim

e a largura de 14 cm.

O relatório deverá ter sua propriedade Popup definida como Sim.

Veja abaixo como será o modelo do cupom de venda no modo de visualização:

Sistema de Exemplo

Novamente será disponibilizado o link para download do sistema de vendas, desta vez

finalizado e totalmente funcional.

Page 101: ACCESS 2010_Classes.pdf

101

Continua a recomendação de consultar o exemplo apenas para tirar dúvidas e verificar

como foi feito, além de ver o sistema em funcionamento. O treinamento ainda é a

maneira recomendada de aprender.

Segue o link para download

Venda00.zip

A fim de auxiliar na resolução de problemas enfrentados pelos leitores que tentam

colocar em prática os ensinamentos deixo aqui a informação sobre quais referências

estão marcadas no editor do VBA. Para isto veja a imagem a seguir.

A versão utilizada para montar o exemplo foi o Access 2007, sendo que salvei o mesmo

no formato do Access 2000, para que todos pudessem acessá-lo normalmente.

Conclusão

Após alguns meses de suado trabalho, de minha parte, e bastante estudo e treinamento,

da parte de vocês leitores, conseguimos finalizar nosso projeto, criando o sistema de

vendas orientado a objetos.

Além da utilização massiva de objetos para desempenhar as funções de cadastro,

cálculo, validação e acesso a dados, aprendemos como criar um PDV simples e também

um modelo de cupom de venda, também bastante simples.

Page 102: ACCESS 2010_Classes.pdf

102

Depois de toda esta cansativa rotina de programação, no caso da digitação de todos

aqueles códigos das classes, não seria maravilhoso que esta tarefa pudesse ser

simplificada? Não seria ótimo que não tivéssemos que nos preocupar com a montagem

dos códigos SQL dos métodos das classes, nem com os métodos de acesso às

propriedades? E quando alteramos um atributo da classe, será que temos que refazer

tudo de novo?

Pois bem, este será o assunto do próximo artigo, no qual será apresentada a ferramenta

Genesis, um aplicativo que cria as classes para o nosso projeto. Você apenas informa

quais são os campos das tabelas e sua descrição, então o Genesis cria o banco de dados

e as classes em um piscar de olhos. Alterou alguma coisa? Basta gerar novamente a

classe e importar para seu projeto outra vez. Simples assim.

Além da criação das classes com o Genesis, veremos dicas de como agilizar a

importação e a remoção de módulos de nosso projeto, a fim de evitar que tenhamos que

importar ou remover um por um, o que já nos trás um grande aumento de produtividade.

Page 103: ACCESS 2010_Classes.pdf

103

Classes IX - Genesis - A Ferramenta Case

Frequentemente nós, profissionais e amadores da área de informática, nos deparamos

com algumas tarefas extremamente chatas existentes no desenvolvimento de sistemas,

algumas delas relacionadas aos trabalhos repetitivos e cansativos, como, por exemplo, a

documentação de atributos e a programação de métodos básicos de classes, ou seja,

aqueles que atribuem ou retornam valores, buscam, salvam ou excluem um objeto, entre

outros.

Segundo criadores de sistemas análogos, o trabalho de programação pode ser reduzido,

em média, até 60%, ao se utilizar os geradores de código. Isto permite que o

profissional concentre-se apenas em implementar os métodos inerentes às regras do

negócio, diminuindo consideravelmente o tempo necessário para a conclusão do projeto.

Algumas das ferramentas de geração de código existentes mantém o seu foco na criação

de classes a partir de um Banco de Dados pronto, conectando-se ao mesmo e buscando

as informações sobre a estrutura das tabelas e relacionamentos. Outras geram as classes

a partir dos modelos de projeto. Existem também algumas especializadas em modelar o

próprio esquema do Banco de Dados, fornecendo os script´s SQL para a criação do

mesmo. Umas mais simples, outras nem tanto, a verdade é que nunca encontramos

aquela que atende às nossas necessidades completamente.

O Genesis, que é uma opção a mais, é uma ferramenta de desenvolvimento que busca a

união entre os esforços de documentação, criação do Banco de Dados e programação,

auxiliando na construção do software, a partir dos dados inseridos pelo usuário uma

única vez, nestes três aspectos básicos:

Geração do Banco de Dados, com todas as tabelas e seus respectivos relacionamentos;

Geração do código das classes, uma para cada tabela, contendo os atributos e os

métodos básicos, além da classe de conexão com o BD e o módulo de importação de

classes;

Geração dos relatórios de estrutura das tabelas, dicionário de dados e scripts de

criação das tabelas, podendo servir para análise do esquema ou fazer parte da

documentação do sistema.

Page 104: ACCESS 2010_Classes.pdf

104

Para alcançarmos nosso objetivo de programar orientado a objetos, agora utilizando

ferramentas que aumentem nossa produtividade, nesta etapa vamos conhecer um pouco

mais do Genesis, e descobrir como ele poderá nos ajudar em nossas atividades.

Utilizando o Genesis

A ferramenta foi desenvolvida no padrão do Access 2000, para que possa ser utilizado

pelo maior número de usuários. Além das bibliotecas padrão do Access, ele utiliza as

seguintes referências, na ordem em que aparecem:

OLE Automation

Microsoft ActiveX Data Objects 2.1 Library

Microsoft DAO 3.6 Object Library

Caso sua versão possua referências diferentes, desmarque as existentes, que deverão

estar indicadas como " AUSENTES ", e procure uma equivalente, a mais próxima

possível. Normalmente elas têm o mesmo nome, alterando apenas o número da versão.

Quando encontrá-la marque, compile e teste o programa até que encontre todas as

bibliotecas necessárias.

Visando padronizar o estilo das classes e do banco de dados que serão criados, siga os

padrões propostos para nomear tabelas e atributos, além de inserir descrições conforme

será apresentado nos próximos tópicos. Caso você utilize outro padrão a funcionalidade

não será afetada, mas os atributos, as tabelas e as classes geradas pelo Genesis tem seus

Page 105: ACCESS 2010_Classes.pdf

105

nomes modificados ou são acrescentadas iniciais que podem prejudicar a estética do

sistema caso as regras não seja seguidas.

Como todo bom software livre o código do Genesis é aberto, e você pode realizar

modificações a seu critério para personalizar a padronização dos nomes de tabelas,

atributos e classes.

Campos e Comandos do Sistema

A figura abaixo identifica cada um dos botões de comando e campos da tela principal

do Genesis. Utilize-a como referência para os tópicos seguintes, que esclarecerão com

mais detalhes o funcionamento do sistema.

Trabalhando com Tabelas

Padrão proposto para nomes de tabelas:

:: Primeira letra em maiúscula;

:: Letras restantes em minúscula;

:: Nomes compostos por mais de uma palavra separados por maiúscula;

:: Não utilize acentos ou cedilha.

Ex: Departamento, Produto, Cliente, TipoCliente e CategoriaProduto

Page 106: ACCESS 2010_Classes.pdf

106

Quando o Genesis cria uma classe para a tabela é acrescentado o prefixo cls no início do

nome da mesma, resultando em uma classe com a inicial minúscula e as separações em

maiúscula. Os exemplos acima ficariam assim:

Ex: clsDepartamento, clsProduto, clsCliente, clsTipoCliente e clsCategoriaProduto

Caso você colocasse um nome, por exemplo, em minúscula, não haveria a separação das

palavras. Nomes com underscore também prejudicariam a estética, resultando em

nomes de classe da seguinte maneira:

Ex: clsdepartamento, clsPRODUTO, clsTipo_Cliente e clsCATEGORIA_PRODUTO

Para criar uma nova tabela clique no botão Novo (1). Será criado um registro em

branco.

Coloque o nome da tabela que deseja criar no campo Tabela/Classe (2), e a descrição

da mesma ao lado, no campo Descrição (3), para que esta seja adicionada aos relatórios

de documentação (estrutura da tabela e dicionário de dados) e ao relatório SQL.

Apenas as tabelas que estiverem com o campo Criar (4) marcado serão exportadas

quando o botão Exportar Classes (5) for clicado. Para excluir uma tabela clique no

botão Excluir (7). Se uma tabela for excluída todos os seus campos também serão

automaticamente eliminados.

Para navegar entre tabelas e pesquisar utilize os botões de navegação (5) e pesquisa

(6).

Depois de criada a tabela inclua os atributos.

Trabalhando com Campos da Tabela

Padrão proposto para os campos das tabelas:

:: Primeira letra em minúscula;

:: Letras restantes em minúscula;

:: Nomes compostos por mais de uma palavra separados por maiúscula;

:: Campos de chave primária ou estrangeira em que será utilizado um código inclua a

inicial cod ou id no nome do campo;

:: Não utilize acentos ou cedilha.

Ex: codDepartamento, descricao, valor, codCliente, idCliente, dataNascimento,

mesEntradaProduto e categoriaProduto

Quando o Genesis cria um atributo de classe para um campo de tabela é acrescentado

um prefixo que indica o tipo de dado, conforme a descrição a seguir:

Page 107: ACCESS 2010_Classes.pdf

107

String (texto) → str

Date/Time (data/hora) → dtm

Integer (inteiro) → int

Long (inteiro longo) → lng

Single (decimal simples) → sgl

Double (decimal duplo) → dbl

Currency (valor monetário) → cur

Object (objeto) → obj

Recordset (conjunto de registros) → rst

Boolean (lógico) → boo

Além disso a primeira letra do nome do atributo é convertida para maiúscula para

manter o padrão. Os exemplos acima ficariam assim:

Ex: intCodDepartamento, strDescricao, curValor, intCodCliente, lngIdCliente,

dtmDataNascimento, intMesEntradaProduto e strCategoriaProduto

Os próximos tópicos descrevem como configurar os campos da tabela a serem criados.

Chave Primária

Marque o campo PK (17) para indicar que o atributo é ou faz parte da chave primária da

tabela. Ao indicar um campo como chave primária ele aparecerá na caixa de

combinação do campo Atributo FK (22) de outras tabelas, para que possa ser usado

como chave estrangeira.

Obs: Atributos do tipo Memo ou Object não podem ser chave primária.

Nome do Atributo

Informe no campo Atributo (18) neste campo o nome do atributo, de acordo com o

padrão apresentado para nomes de campos de tabela.

Campo Obrigatório

Marque este campo para indicar que o atributo é obrigatório e não pode conter um valor

nulo.

Tipo de Dado

Escolha o tipo de dado para o atributo. Os tipos possíveis são:

String → Texto com até 255 caracteres;

Memo → Texto com tamanho indeterminado;

Date/Time → Data e/ou hora, tamanho 8 bytes;

Integer → Número inteiro com 2 bytes de tamanho (-32.768 a 32.767);

Long → Número inteiro longo com 4 bytes

de tamanho (-2.147.483.648 a 2.147.483.647);

Single → Decimal com ponto flutuante com 4 bytes

de tamanho (±3,402823E38 a ±1,401298E-45);

Double → Decimal com ponto flutuante com 8 bytes

Page 108: ACCESS 2010_Classes.pdf

108

de tamanho (±1,79769313486232E308 a ±4,94065645841247E-324);

Currency → Número com ponto fixo com 15 dígitos à esquerda da vírgula

e

4 dígitos à direita da vírgula, utilizado para cálculos de precisão

por

envolver valores em

dinheiro (-922.337.203.685.477,5808 até 922.337.203.685.477,5807);

Object → Endereços com tamanho de 4 bytes, que se referem a

objetos (Imagens, documentos, planilhas, etc...);

Boolean → Número com tamanho de 2 bytes que representa os valores

lógicos True

e False. A equivalência entre os valores e os números é 0 para False e

qualquer

outro número para True.Um valor True convertido para número retorna 1.

Tamanho do Campo

Informe no campo Tamanho (21) a quantidade máxima de caracteres para campos do

tipo String. O tamanho mínimo permitido é 1 e o máximo é 255 caracteres. Caso seja

colocado um valor fora do intervalo o Genesis informará o erro e colocará o valor

padrão. Os outros tipos de campo não podem ter tamanho de campo diferente do padrão.

Estes são os tamanhos padrão para cada tipo de campo:

String → 30;

Memo → 0 (Não há limite definido!);

Currency, Double e Date/Time → 8;

Integer e Boolean → 2;

Object, Long e Single → 4.

Chave Estrangeira (Foreign Key)

Indique no campo Atributo FK (22) o atributo (chave primária da tabela de destino) que

servirá de referência para a chave estrangeira na tabela à qual estará vinculado.

Os possíveis atributos são listados e podem ser acessados inclusive a partir da mesma

tabela. Isto ocorre quando, por exemplo, um atributo referencia outro atributo da mesma

tabela, criando um auto-relacionamento. Esta situação poderia ocorrer em casos como o

de uma empresa onde um funcionário é chefe de outro, ou um departamento é

subordinado a outro, ou quando um produto é componente de outro, e a melhor forma

de mapear este relacionamento seja uma tabela única.

Você só pode criar uma chave estrangeira que referencie um campo de chave primária

de outra tabela, ou da mesma tabela, se os dois campos forem do mesmo tipo. Como

exemplo um campo do tipo Integer não pode referenciar um String, e assim

sucessivamente.

Ao vincular campos de chave estrangeira o Genesis criará os relacionamentos com

integridade referencial, porém não incluirá os eventos em cascata para atualização e

exclusão de dados. Caso seja necessária, esta configuração deverá ser feita

manualmente pelo desenvolvedor no banco de dados criado pelo Genesis.

Page 109: ACCESS 2010_Classes.pdf

109

Tipo de Chave Estrangeira

Ao incluir uma chave estrangeira na tabela com certeza você fará uso desta ligação

também nas classes. Logo devemos informar o tipo de chave estrangeira no campo Tipo

FK (23). Para compreender a utilidade deste recurso, imagine os dois casos a seguir:

No primeiro temos uma relação entre Fita e Categoria, duas classes de uma locadora

de fitas de vídeo. Nesta locadora o valor de locação não é colocado individualmente nas

fitas. Elas são classificadas em categorias, como Lançamento, Catálogo, Infantil e

Promoção, para que seja facilitado o trabalho de alteração de preços. Ao se modificar o

valor de locação de uma categoria todas as fitas estarão atualizadas automaticamente.

1º Caso: Descrição de Tipo (DT)

Veja bem, no código da classe Fita deverá existir um método novaLocacao() ou algo

parecido, que será responsável pela efetivação de uma locação de fita. Para calcular o

valor da locação o método teria que instanciar a classe Categoria, verificar a que

categoria a fita pertence, através do atributo intCategoria, e solicitar a ela o valor da

locação.

Até aí tudo bem, mas então qual a utilidade do recurso Descrição de Tipo? Pois bem,

este recurso cria automaticamente um atributo do tipo de objeto da classe que precisa

ser instanciada (Categoria), e toda vez que o atributo de chave estrangeira intCategoria

é atualizado, a referência à classe Categoria também é atualizada através do atributo

objeto criado.

No exemplo dado os atributos da classe Categoria podem ser acessados através da

classe Fita, da seguinte maneira:

'Declaramos algumas variáveis conforme a necessidade

Dim curPrecoLocacao As Currency

Dim strDescricao As String

'Declaramos e instanciamos o objeto Fita

Dim objFita As New clsFita

'Obtemos o objeto fita cujo código é 1012

Page 110: ACCESS 2010_Classes.pdf

110

objFita.obter(1012)

'Acessamos os atributos da classe Categoria

strDescricao = objFita.objCategoria.descricao

curPrecoLocacao = objFita.objCategoria.valorLocacao

'De dentro da classe Fita o acesso seria mais simples, da seguinte

maneira

strDescricao = objCategoria.descricao

curPrecoLocacao = objCategoria.valorLocacao

Vamos analisar agora o segundo caso, o Vetor de Registro (VR). A descrição de tipo

serve para buscarmos um valor único em outra classe, mas imagine, como no exemplo

abaixo, um Departamento que queira obter uma relação com todos os Funcionários

que trabalham no mesmo. Uma solução seria criar um Recordset, executar uma

consulta e navegar através dele para coletarmos os dados desejados.

Visando facilitar este trabalho, ao se definir uma chave estrangeira como VR, o Genesis

inclui automaticamente um método vetorNomeDaClasse() na classe atual, cujo valor

de retorno é exatamente um Recordset contendo todos os objetos que pertencem ao

objeto que possui o método, neste caso todos os funcionários que pertencem ao

departamento.

2º Caso: Vetor de Registro (VR)

Veja no modelo de classes que, após definir intDepartamento como chave estrangeira

do tipo VR, foi criado o método vetorFuncionario() na classe Funcionario, o qual

utiliza o valor do atributo para saber a que Departamento pertence o funcionário. A

consulta é feita via SQL, diretamente no banco de dados, mas a atribuição dos valores

foi originada anteriormente pelos atributos do objeto.

Além disso foram incluídos dois atributos na classe estrangeira, aquela que necessitava

da relação de registros da outra classe. Foram criados um objeto da classe que contém o

VR e um Recordset que recebe os registros retornados da consulta. A operação é

executada toda vez que os atributos chave da classe estrangeira são atualizados. Neste

Page 111: ACCESS 2010_Classes.pdf

111

caso quando codDep é alterado pelo procedimento Property Let codDep(), os atributos

objFuncionario e rstFuncionario também são atualizados pelo procedimento.

A partir daí podemos navegar pelo Recordset rstFuncionario normalmente através da

classe Departamento, ou acessar suas propriedades, da seguinte maneira:

'Navegando pelo Recordset, buscando o próximo registro

objDepartamento.rstFuncionario.moveNext

'Verificando a quantidade de registros de funcionários

objDepartamento.rstFuncionario.recordCount

'Acessando um atributo do funcionário

objDepartamento.rstFuncionario.Fields("nome")

Obs: Perceba que ao acessarmos um atributo pelo recordset devemos

utilizar o

nome original do mesmo, pois o prefixo str adicionado existe somente

dentro

da classe.

Devemos nos lembrar que em nenhum momento o programador necessita instanciar as

classes ou os Recordsets para implementar estes recursos, pois o Genesis deixa todo o

código pronto. Ao programador cabe apenas instanciar a classe com a qual vai trabalhar

e fazer uso das facilidades apresentadas.

Importante:

* O recurso Descrição de Tipo só é implementado automaticamente quando a classe

estrangeira possui chave primária única. Quando a classe estrangeira possui chave

primária composta por mais de um atributo o Tipo FK será ignorado.

* O recurso Vetor de Registro só é implementado automaticamente quando as duas

classes possuem chave primária única. Nas classes em que a chave primária é composta

de mais de um atributo o Tipo FK será ignorado.

Ordem da Chave Estrangeira

Para definir a ordem das chaves estrangeiras no banco de dados a ser criado devemos

informá-la no campo Ordem (24).

Este recurso tem a única, mas não menos importante, utilidade de separar chaves

estrangeiras para uma mesma chave primária da tabela estrangeira. Isto ocorre quando

temos dois ou mais atributos semelhantes em uma tabela fazendo referência ao mesmo

atributo FK de outra tabela. Raramente isto acontece, mas no caso de ocorrer lembre-se

de utilizar a Ordem, ou ocorrerá um erro tanto na criação da tabela quanto da classe.

Para ilustrar melhor a necessidade veja um exemplo prático. Em um hospital os médicos

trabalham por escala de plantão. Digamos que o sistema do hospital mantém o registro

das equipes que concorrem ao plantão diariamente. Suponha que o BD esteja

organizado mais ou menos assim:

Page 112: ACCESS 2010_Classes.pdf

112

Podemos notar claramente que o sistema guarda os registros do médico que estava

escalado para o plantão e o médico que efetivamente tirou o plantão. Quando os dois

códigos são iguais significa que não houve substituição. Mas o importante é perceber

que tanto o atributo MedicoEscalado quanto MedicoSubstituto da tabela Plantao

referenciam a mesma chave primária da tabela Medico, ou seja, o atributo Codigo.

Para que o Genesis não confunda um caso como este com um caso de chave composta

por mais de um atributo, você deve diferenciar os atributos FK definindo Ordens

diferentes para os mesmos.

Poderíamos definir o campo Ordem para o atributo MedicoEscalado com o valor 1 e

para MedicoSubstituto com o valor 2, por exemplo. Nos casos de chave composta deve

ser mantida a mesma Ordem para todos os atributos, para o caso de apenas um conjunto

de chave estrangeira, ou uma ordem para cada conjunto, no caso de haver mais de um.

Em resumo, a Ordem representa uma seqüência, ou conjunto, de chaves estrangeiras

para uma mesma chave ou conjunto de chaves primárias.

Descrição do Atributo

Informe no campo Descrição (25) os detalhes que esclareçam a função do atributo, para

que ela seja adicionada aos relatórios de documentação (estrutura da tabela e dicionário

de dados) e aos comentários da classe. A descrição pode ter até 150 caracteres.

Lembre-se de utilizar texto que deixe claro a utilidade do atributo, e que esteja livre de

erros de ortografia ou gramática, zelando, assim, pela estética da documentação e do

sistema que será gerado.

Para campos de chave primária, a sugestão é colocar a sigla “PK – “ (Primary Key) no

início da descrição, para identificá-los como tal. Já para campos de chave estrangeira, a

sugestão é colocar a sigla “FK – “ (Foreign Key).

Excluindo um Atributo

Para excluir um atributo basta clicar no botão que contem uma lixeira (26) e confirmar

quando o sistema solicitar.

Gerando uma Classe

Page 113: ACCESS 2010_Classes.pdf

113

Para gerar o código da classe atual clique no botão Gerar Classe (13). O código será

criado e apresentado em um formulário independente. O campo Criar (4) não precisa

estar marcado para a utilização deste comando.

Um conhecimento prévio dos conceitos de Orientação a Objetos auxilia na compreensão

dos códigos desta parte. Em caso de dúvida consulte o restante do material ou uma das

referências apresentadas anteriormente para se aprofundar no assunto.

Primeiramente vamos conhecer a estrutura completa de uma classe gerada pela

ferramenta Genesis.

Nome da Classe → Conforme descrito anteriormente, o nome da classe é criado

adicionando-se o prefixo cls ao nome da tabela.

clsNomeDaTabela

Atributos → É criado um atributo para cada campo da tabela. Para cada campo de

chave primária é criado também um atributo de backup, utilizado pelo método salvar(),

pois no caso de ocorrer uma alteração de um atributo chave não seria mais possível

atualizar o BD pelo novo valor. Neste caso o método salvar() não faria efeito, então ele

utiliza o valor do backup para executar a consulta atualização, em seguida altera todos

os atributos para os novos valores, caso a operação ocorra com sucesso. Além destes

atributos particulares de cada classe, são criados dois atributos genéricos,

Page 114: ACCESS 2010_Classes.pdf

114

booChaveAlterada e booAtributoAlterado, ambos lógicos, utilizados para indicar

alterações nos valores de atributos chaves e atributos comuns, respectivamente. Estes

atributos não possuem função específica, e podem ser utilizados pelo desenvolvedor

conforme a necessidade, quando este quiser saber se uma chave ou atributo tiveram seus

valores modificados. Os atributos do tipo objeto e recordset automáticos são criados

caso exista algum atributo do tipo Descrição de Tipo (DT) ou Vetor de Registro (VR).

booChaveAlterada

booAtributoAlterado

bkpAtributoIdentificador1

tipoAtributoIdentificador1

: :

[bkpAtributoIdentificadorN]

[tipoAtributoIdentificadorN]

tipoAtributoExtra1

[tipoAtributoExtraN]

Métodos de acesso aos Atributos → Para cada atributo originado de um campo da

tabela são criados dois métodos, um para atribuir valor (Property Let, ou Property Set

para objetos) e outro para recuperar valor (Property Get). Dentro destes métodos podem

existir funções extras, como as que implementam o VR, dependendo do contexto.

Property Get chaveAlterada ( )

Property Get atributoAlterado( )

Property Let atributoIdentificador1( )

Property Get atributoIdentificador1( )

: :

Property Let atributoIdentificadorN( )

Property Get atributoIdentificadorN( )

Property Let atributo1( )

[Property Set atributo1( )]

Property Get atributo1( )

: :

Property Let atributoN( )

Property Get atributoN( )

[Property Get objNomeDoObjeto1( )]

: :

[Property Get objNomeDoObjetoN( )]

Métodos construtor e destrutor → Os métodos construtor e destrutor são criados sem

qualquer código executável. Apenas a estrutura deles é gerada. Para utilizá-los basta

inserir código dentro deles. Todo código que estiver dentro do método class_initialize()

será executado sempre que um objeto da classe for instanciado. Da mesma forma todo

código dentro de um método class_terminate() será executado sempre que a classe

encerrar a sua existência, mas antes que isto realmente ocorra.

class_initialize( )

class_terminate( )

Page 115: ACCESS 2010_Classes.pdf

115

Métodos de acesso ao Banco de Dados → São os métodos básicos de acesso ao banco

de dados, utilizados para realizar a persistência dos objetos. O método obter() é

utilizado para a recuperação de um objeto, recebendo como parâmetro o(s) valor(es)

do(s) atributo(s) chave da classe, e realizando uma consulta a partir deste(s) valor(es). O

método incluir() faz o oposto. Depois de definidos os valores dos atributos, este método

os coleta e inclui o novo objeto no banco de dados, tornando-o persistente. O método

salvar() grava as alterações feitas aos atributos do objeto no banco de dados. Um objeto

só pode ser salvo se já existia anteriormente. Objetos novos devem ser incluídos antes

que se possa salvá-los. Antes de salvar um objeto o método verifica se o mesmo já não

existe no banco de dados, utilizando o método existe(), que apenas checa a existência de

um registro com o mesmo valor de chave na respectiva tabela. O método excluir()

apaga o registro referente ao objeto no banco de dados. Todos este métodos retornam

verdadeiro caso a operação ocorra com sucesso, ou falso em caso contrário.

existe( )

incluir( )

excluir( )

obter( )

salvar( )

Limpar → Método que redefine todos os atributos de volta aos seus valores iniciais, ou

seja, atribui o valor Nulo para todos os atributos e False para os atributos

booChaveAlterada e booAtributoAlterado. O método é executado toda vez que um

objeto é excluído com sucesso, imediatamente após o término da operação. Você pode

utilizá-lo a qualquer momento para "limpar um objeto".

limpar()

Vetor de Registro (VR) e Descrição de Tipo (DT) → Os atributos e o método criados

para a implementação da descrição de tipo e do vetor de registro foram detalhados no

item que trata sobre o campo TipoFK. São os objetos que referenciam outra classe para

obter valores de atributos da mesma, no caso da DT, ou uma relação de registros, no

caso do VR. Estes atributos e o método são gerados apenas quando o usuário define

uma chave estrangeira com um dos dois tipos.

[objNomeDaClasse]

[rstNomeDaClasse]

[objetoNomeDoObjeto]

[vetorNomeDaClasse( )]

Gerando o Código SQL da Tabela

Para gerar o script SQL de criação da tabela clique no botão Gerar SQL (14). O código

será criado e uma mensagem de confirmação informará o sucesso da operação.

Visualizando o Código SQL da tabela e o Código da Classe

Para visualizar o script SQL de criação da tabela clique no botão Código SQL (16). O

código será apresentado em um formulário independente. O código pode ser copiado ou

alterado, mas esta alteração não fará efeito na criação do Banco de Dados.

Page 116: ACCESS 2010_Classes.pdf

116

Para visualizar o código da classe clique no botão Código da Classe (15). O código

será apresentado em um formulário independente. O código pode ser copiado ou

alterado, mas sua alteração não fará efeito na exportação das classes.

Visualizando o Relatório de Estrutura das Tabelas

Para visualizar o relatório de estrutura das tabelas clique no botão Listar Tabelas (10).

O relatório com as informações solicitadas será apresentado.

Visualizando o Dicionário de Dados

Para visualizar o dicionário de dados clique no botão Dicionário de Dados (11). O

relatório com as informações solicitadas será apresentado.

Visualizando o Relatório SQL

Para visualizar o relatório de código SQL das tabelas clique no botão Código SQL (12).

O relatório com as informações solicitadas será apresentado. Para exportá-lo para o

Word utilize a função Publicar com o MS Word

Gerando o Banco de Dados

Para gerar o banco de dados completo clique no botão Banco de Dados (8). A caixa de

diálogo do Windows Salvar Como será apresentada. Escolha a pasta e o nome do novo

banco de dados e clique em Salvar. Caso não ocorram erros uma mensagem será

apresentada ao término do processamento informando que o BD foi gerado com

sucesso.

Para colocar o projeto em andamento, exporte as classes para uma pasta e, em seguida,

importe-as para o BD que acaba de ser criado. Para isso abra o editor do Visual Basic e

vá ao menu Arquivo / Importar Arquivo e inclua as classes. Esta operação só permite

a importação de uma classe por vez, então seja paciente. Para ajudar com esta

importação, ou mesmo a atualização de classes, o Genesis inclui o módulo IRModulos,

que contem as funções importaClasses() e removeClasses(), que serão detalhadas em

um tópico a parte.

Page 117: ACCESS 2010_Classes.pdf

117

Na ocorrência de erros cada um deles será informado, sendo que isto não interrompe o

processo de criação do BD. As mensagens tentarão informá-lo sobre o erro para que

seja corrigido. Ao final será apresentada a mensagem de conclusão, na qual constará o

número de erros ocorridos.

A mensagem final irá sugerir a você que verifique e organize a estrutura estética dos

relacionamentos, pois eles são criados em ordem aleatória, fazendo com que as tabelas

fiquem em posições que deixam as linhas dos relacionamentos cruzando-se entre si, de

maneira totalmente caótica. Nada que interfira no funcionamento, mas para que você

mantenha seu modelo adequadamente limpo, um pouco de ordem não fará mal.

A Classe de Conexão

A classe aclConexaoBD será incluída no banco de dados criado, possibilitando a

utilização imediata a partir das outras classes ou qualquer outra função que necessite

acesso às tabelas via SQL. As classes geradas pelo Genesis já utilizam a classe de

conexão.

Importando e Removendo Módulos

A fim de evitar que os usuários tenham que importar ou remover módulos

individualmente do sistema, utilizando o menu do editor do VBA, ou a combinação de

teclas Ctrl+M, foi incluído no Genesis o módulo IRModulos, que possui duas funções,

uma para importar e outra para remover módulos em grupo.

Os procedimentos devem ser executados manualmente pelo desenvolvedor, que deverá

ajustar as variáveis que indicam o caminho da pasta onde se encontram as classes,

posicionar o cursor dentro do procedimento desejado e teclar F5 ou abrir o menu

Executar => Executar Sub/UserForm no menu do editor do VBA.

Este é o código dos procedimentos do módulo:

Sub importaClasses()

'Como utilizar este procedimento para

'importar seus módulos: primeiro crie as

'classes utilizando o Genesis, exporte-as

'para uma pasta qualquer, altere o endereço

'da variável caminho abaixo, e execute o

'procedimento, posicionando o cursor dentro

'do código e pressionando a tecla F5.

Dim fs, pasta, arquivos, arquivo

Dim caminho As String

Dim nomeCompleto As String

Page 118: ACCESS 2010_Classes.pdf

118

Dim nomeArquivo As String

'Altere o caminho da pasta para o

'local onde estão as suas classes

'a serem importadas.

caminho = "C:\MeuProjeto\Classes"

If caminho <> "" Then

Set fs = CreateObject("Scripting.FileSystemObject")

Set pasta = fs.GetFolder(caminho)

Set arquivos = pasta.Files

For Each arquivo In arquivos

nomeArquivo = arquivo.Name

If Left(nomeArquivo, 3) = "cls" Then

nomeCompleto = arquivo.Path

Application.VBE.ActiveVBProject.VBComponents.Import

nomeCompleto

End If

Next

End If

End Sub

Sub removeClasses()

'Para remover os módulos execute o

'procedimento posicionando o cursor

'dentro do código e pressionando F5.

Dim componentes, componente

Dim nomeComponente As String

Set componentes = Application.VBE.ActiveVBProject.VBComponents

For Each componente In componentes

nomeComponente = componente.Name

If Left(nomeComponente, 3) = "cls" Then

Application.VBE.ActiveVBProject.VBComponents.Remove

componente

End If

Next

End Sub

Caso seja necessário realizar alguma alteração em qualquer dos atributos ou das tabelas,

incluir ou retirar campos, ou mesmo corrigir descrições, remova as classes do projeto,

faça as alterações no Genesis, exporte novamente as classes e importe-as novamente.

Tudo isto pode ser feito em questão de minutos.

Tenha o cuidado de deletar as classes exportadas anteriormente, pois quando elas são

sobrepostas e a nova classe for menor que a anterior, o final da primeira não será

apagado, resultando em uma classe com erros no código.

Obs: Perceba que os procedimentos testam se o nome do componente é iniciado pelo

prefixo cls. Logo somente módulos que se iniciam com o prefixo serão importados ou

removidos. Para importar ou remover outros módulos basta ajustar o prefixo conforme a

Page 119: ACCESS 2010_Classes.pdf

119

necessidade. Este modelo apenas foi ajustado para trabalhar com as classes criadas pelo

Genesis, cujos nomes se iniciam por cls.

Exportando as classes

Para gerar e exportar todas as classes de uma só vez clique no botão Exportar Classes

(9). A caixa de diálogo do Windows Procurar Pasta será apresentada. Escolha a pasta

para onde deseja exportar suas classes e clique em OK. Caso não ocorram erros uma

mensagem será apresentada ao término do processamento informando que as classes

foram exportadas com sucesso e exibindo o caminho completo da pasta escolhida.

Atenção: Somente as tabelas que estiverem com o campo Criar (4) marcado serão

geradas e exportadas.

Encerrando o Sistema

Para encerrar o Genesis basta clicar no botão de encerramento (27), localizado no

canto superior direito da tela principal.

Download do Genesis

Será disponibilizado o link para download do Genesis, assim você poderá sempre obter

a última versão do sistema, contendo as atualizações mais recentes.

Genesis.zip

Utilizando este sistema com toda certeza seu trabalho de desenvolver projetos

orientados a objetos no Access/VBA será reduzido consideravelmente. Planeje seu

modelo de banco de dados, transcreva para o programa, exporte suas classes, gere seu

banco de dados e importe as classes. Pronto, seu novo projeto está iniciado.

Conclusão

Depois de aprender a trabalhar com classes e objetos, codificando manualmente todos

os atributos e métodos chega a hora de conhecer uma forma de automatizar esta tarefa.

A ferramenta Genesis nos possibilitou esta grande ajuda, poupando-nos tempo e

esforço.

Vimos como criar tabelas e incluir campos, ajustando seu tamanho, tipo e referências.

Vimos também como incluir informações para a documentação do sistema. Finalmente

pudemos verificar como agilizar a inclusão ou remoção de módulos de nosso projeto

criado. Todas estas facilidades complementam o conhecimento adquirido durante o

aprendizado decorrente dos meses de estudo.

Este artigo foi uma pequena adaptação da ajuda contida no programa, resultado de uma

revisão geral e a conseqüente atualização da versão anterior do Genesis, incluindo o

próprio arquivo de ajuda.

E agora, que caminho seguir? Como continuar a jornada do aprendizado?

Page 120: ACCESS 2010_Classes.pdf

120

Calma, no próximo artigo, o último da série, faremos uma abordagem de como utilizar

os objetos presentes no MS-Office para aprimorar seus projetos e direcionar suas novas

pesquisas. Novas fronteiras serão visualizadas, prontas para serem exploradas.

Até lá então...

Page 121: ACCESS 2010_Classes.pdf

121

Classes X - Conclusão

Após a longa jornada, na qual aprendemos a criar nossos próprios objetos, aplicando-os

em nossos projetos baseados em Visual Basic for Applications, chega o momento da

despedida. Com isso chega também a hora em que o desenvolvedor iniciará sua

caminhada solitária rumo ao aperfeiçoamento de suas habilidades.

Como prosseguir? O que devo fazer agora? Como aprofundar e aprimorar o que foi

aprendido? Onde buscar novos conhecimentos? Como me atualizar constantemente?

Este último artigo da série tentará responder algumas destas perguntas, com o intuito de

abrir a sua mente e fornecer caminhos para que você possa seguir em frente.

Utilizando os Objetos do Sistema

Praticamente todos os itens em um software desenvolvido em Access são objetos.

Sendo assim estes objetos podem ser acessados e trabalhados. Conhecendo seus

métodos, propriedades e eventos fica bem mais fácil para o desenvolvedor aproveitar

funcionalidades já existentes para construir seus aplicativos.

Entre os itens mais utilizados em um sistema Access/VBA estão o formulário e o

relatório, com seus controles, o recordset e o objeto DoCmd. Além destes existem

dezenas, ou centenas, de outros objetos que podem ser utilizados, mas estes são os

exemplos mais comuns e mais simples disponíveis.

Você pode realizar qualquer tarefa com um formulário ou relatório, bem como dos

controles existentes no mesmo, através de linhas de código. Para isto basta acessar o

objeto. Estando em um módulo de um formulário ou relatório você pode acessar seus

métodos e propriedades utilizando a palavra chave Me. Como exemplo, depois de

alterarmos algum dado na fonte de origem de um formulário e desejarmos que as

alterações sejam exibidas imediatamente para o usuário, basta realizarmos uma

chamada ao método Requery do mesmo para que as informações sejam atualizadas.

Neste caso fazemos a chamada diretamente, sem a necessidade de instanciar o objeto,

assim:

'Atualizando o conjunto

'de registros do formulário

Me.Requery

Caso seja necessário acessar um objeto formulário a partir de outro módulo devemos

primeiro instanciá-lo, pois seus métodos e propriedades não estarão acessíveis antes

disso.

'Definindo a variável de objeto

'para o formulário.

Dim frmCliente As Form

'Definindo a constante de twips

'para cálculo de centímetros

Const intTwips = 567

Page 122: ACCESS 2010_Classes.pdf

122

'Atribuindo o formulário FCliente

'à variável de objeto formulário

Set frmCliente = Form_FCliente

'Exibindo a legenda do formulário

'através da propriedade Caption

MsgBox frmCliente.Caption

'Alterando a propriedade Permitir

'Edição do formulário

frmCliente.AllowEdits = False

'Movendo o formulário para a posição de

'esquerda a 10cm e superior a 5cm

frmCliente.Move 10 * intTwips, 5 * intTwips

Para trabalhar com acesso aos dados armazenados nas tabelas podemos utilizar um

objeto do tipo recordset. Veja o exemplo que permitiria buscar os registros da tabela

Cliente e exibir o nome de cada cliente.

'Definindo a variável para

'consulta SQL

Dim strSql As String

'Definindo uma nova variável de objeto

'recordset para conjunto de registros

Dim rstCliente As New ADODB.Recordset

'Montando a consulta SQL

strSql = "Select * From Cliente"

'Abrindo o recordset

rstCliente.Open strSql, CurrentProject.Connection, adOpenStatic,

adLockReadOnly

'Exibindo o total de clientes

MsgBox "Total de clientes: " & rstCliente.RecordCount

'Exibindo o nome de cada um dos

'clientes existentes no recordset

While Not rst.EOF

MsgBox "Nome do Cliente " & rstCliente.AbsolutePosition & ": " & _

rstCliente("nomeCliente")

rstCliente.MoveNext

Wend

'Fechando o recordset

rstCliente.Close

Agora vamos supor que você tem um botão em cada um de seus formulários cuja

função é habilitar a edição dos dados, pois criou todos os formulários bloqueados para

edição. Enquanto a edição estiver liberada o formulário deverá mudar de cor para alertar

o usuário que ele está em modo de edição. O código do seu botão seria parecido com

este:

Sub btnLiberaEdicao_Click()

'Definindo a cor da seção detalhe para amarelo

Me.Section(acDetail).BackColor = vbYellow

Page 123: ACCESS 2010_Classes.pdf

123

'Definindo a propriedade permitir edição = true

Me.AllowEdits = True

'Atribuindo uma legenda informando que o formulário

'está liberado para edição

Me.Caption = "Atenção: Edição Liberada"

End Sub

Este código funcionaria corretamente liberando o formulário. O problema é que você

teria que colocá-lo em todos os botões de liberação de todos os formulários bloqueados.

Como nós já aprendemos o conceito de reutilização queremos aplicá-lo aqui para evitar

que qualquer alteração no código tenha que ser feita em mais de um lugar.

Então devemos criar um procedimento genérico que faça o trabalho independente do

formulário a ser liberado, em um módulo qualquer, onde todo o projeto tenha acesso:

Sub editaFormulario(argForm As Form)

'Definindo a cor da seção detalhe para amarelo

argForm.Section(acDetail).BackColor = vbYellow

'Definindo a propriedade permitir edição = true

argForm.AllowEdits = True

'Atribuindo uma legenda informando que o formulário

'está liberado para edição

argForm.Caption = "Atenção: Edição Liberada"

End Sub

Depois basta chamar o procedimento em qualquer formulário que necessite ser liberado

para edição, passando o formulário como parâmetro para o código:

Sub btnLiberaEdicao_Click()

'Chamando o procedimento que libera

'formulários e passando como argumento

'o próprio formulário

Call editaFormulario(Me)

End Sub

Claro que após a edição e o salvamento dos dados o formulário teria que ser bloqueado

novamente, mas essa parte deixo como exercício prático para você.

O importante é perceber que caso você queira mudar a cor que será usada para

representar a edição do formulário terá que alterar apenas no procedimento

editaFormulario(), já que todos os botões utilizam o mesmo procedimento.

Outro objeto bastante utilizado em qualquer projeto com VBA é o DoCmd. Este é o

objeto responsável por executar as ações do Access a partir de comandos no Visual

Basic for Applications. Ele não precisa ser instanciado, pois é um objeto ativo, já

iniciado com a aplicação. Para utilizá-lo basta chamar um de seus métodos, passando ou

não um parâmetro, dependendo da ação desejada:

'Abrindo o formulário FCliente

DoCmd.OpenForm "FCliente"

Page 124: ACCESS 2010_Classes.pdf

124

'Maximizando uma tela

DoCmd.Maximize

'Fechando uma tela

DoCmd.Close

Para aprender a trabalhar com os objetos fornecidos pelo VBA você pode recorrer à

documentação acessando-a a partir do próprio editor. Pesquise sobre cada objeto que

desejar verificando seus métodos, propriedades e eventos.

Outra maneira ainda mais prática de pesquisar por estas informações é utilizando um

recurso próprio para esta finalidade: o Pesquisador de Objetos. O pesquisador é uma

ferramenta que facilita bastante a pesquisa por métodos, atributos e eventos de objetos

do sistema. Um ponto importante é que ele não se limita a objetos do Access, mas

qualquer código que estiver registrado em sua biblioteca, incluindo os objetos de todos

os aplicativos do Office.

Como exemplo suponha que queremos saber quais são todos os membros do objeto

caixa de combinação (combobox). Ao abrir o pesquisador, basta digitar combobox na

caixa de pesquisa (1), escolher a classe do objeto combobox (2) que todas as suas

propriedades aparecem na lista de membros (3).

Quer saber mais sobre o pesquisador de objetos? Veja o tutorial do amigo Avelino

Sampaio:

http://www.usandoaccess.com.br/tutoriais/tuto2.asp?id=1#inicio

Interagindo com Aplicativos do Office

Além de trabalhar com os objetos internos do Access, o VBA nos permite criar novos

objetos ou mesmo acessar objetos existentes de qualquer aplicativo do Office.

Page 125: ACCESS 2010_Classes.pdf

125

Imagine que você queira montar uma planilha no Excel com os dados das vendas do

mês, existentes no cadastro do seu banco de dados. Ou talvez gerar cartas de proposta

em Word para seus clientes registrados nas tabelas do Access. Mas você quer que o

usuário consiga fazer isto automaticamente, simplesmente clicando em um botão. Então

você deve utilizar os objetos da classe do aplicativo desejado.

O elemento responsável por criar um objeto é a função CreateObject. Para acessar um

objeto existente utilize a função GetObject. Veja os exemplos:

'Inicia o Microsoft Excel e cria um novo objeto PlanilhadeTrabalho.

Set ExcelWorksheet = CreateObject("Excel.Sheet")

'Inicia o Microsoft Excel e abre um objeto PlanilhadeTrabalho

existente.

Set ExcelWorksheet = GetObject("C:\Planilhas\MinhaPlanilha.xls")

'Inicia o Microsoft Word.

Set WordBasic = CreateObject("Word.Basic")

Criando um Objeto Planilha do Excel

Para exemplificar a interação com um objeto do Excel vamos criar uma planilha, incluir

um texto na célula A1, salvar a planilha em uma pasta do computador e fechar o Excel

após a tarefa.

'Declara uma variável de objeto

Dim minhaPlanilha As Object

'Como a variável ainda não foi vinculada faremos

'a vinculação tardia.

Set minhaPlanilha = CreateObject("Excel.Sheet")

'Torna o Excel visível através do objeto Application.

'Observe que o objeto minhaPlanilha possui um

'atributo que também é objeto, o Application, que possui

'outras propriedades internas

minhaPlanilha.Application.Visible = True

'Coloca um texto na célula A1 da planilha

minhaPlanilha.Application.Cells(1, 1).Value = "Esta é a coluna A,

linha 1"

'Salva a planilha no diretório C:\MinhaPlanilha.xls

'Obs: Salve como .xlsx no Office 2007 ou superior

minhaPlanilha.SaveAs "C:\MinhaPlanilha.xls"

'Fecha o Excel com o método Quit no objeto Application

minhaPlanilha.Application.Quit

'Libera a variável de objeto

Set minhaPlanilha = Nothing

Após criar um objeto você poderá acessá-lo novamente utilizando agora a função

GetObject():

'Declara uma variável de objeto

Dim minhaPlanilha As Object

Page 126: ACCESS 2010_Classes.pdf

126

'Busca a planilha criada anteriormente

'Obs: Lembre-se que no Office 2007 ou superior o padrão é .xlsx

Set minhaPlanilha = GetObject("C:\MinhaPlanilha.xls")

'Torna o Excel visível através do objeto Application.

minhaPlanilha.Application.Visible = True

'Tornando a pasta de trabalho visível

minhaPlanilha.Parent.Windows(1).Visible = True

'Coloca um texto na célula A2 da planilha

minhaPlanilha.Application.Cells(2, 1).Value = "Esta é a coluna A,

linha 2"

'Salva a planilha.

minhaPlanilha.Save

'Fecha o Excel com o método Quit no objeto Application

minhaPlanilha.Application.Quit

'Libera a variável de objeto

Set minhaPlanilha = Nothing

Veja o resultado:

As regras anteriores são válidas para qualquer objeto aplicativo diferente daquele em

que se está trabalhando. Com isto você poderá usar sua imaginação para realizar, com

sucesso, a interação entre aplicativos, buscando, exportando e visualizando informações

da maneira que lhe for mais conveniente.

Para saber como programar para cada um dos aplicativos pesquise na documentação que

acompanha o sistema. Ali você encontrará todas as informações necessárias para

compreender e aplicar os conceitos em seus projetos.

Alterações no Modelo de Objetos do Access

A cada nova versão de produtos Office várias alterações são implantadas. Novos itens

são incluídos, outros são alterados e ainda vários são removidos.

Page 127: ACCESS 2010_Classes.pdf

127

Com relação à criação de classes, métodos e propriedades personalizadas não houve

alterações perceptíveis aos usuários em nenhuma das versões, ao logo de todos esses

anos. Houve sim várias modificações no modelo de objetos do sistema.

As tabelas a seguir foram retiradas da documentação do Access 2007, e dizem respeito

às modificações ocorridas comparando-se a versão do Access 2000 com o próprio

Access 2007. Escolhi estas tabelas porque foram as mais resumidas que encontrei. Caso

fosse apresentar todas as evoluções do sistema desde a primeira versão teríamos que

iniciar outra série de artigos. Como o nosso foco é a criação e utilização de objetos,

deixei de lado o restante e trouxe apenas uma amostra de como pesquisar sobre

modificações das versões.

Para encontrá-las você deve abrir a ajuda de qualquer uma das versões, exibir o sumário

e procurar pelo item O que há de novo. O tópico sempre informa as alterações

ocorridas desde a última versão. No caso do Access 2007 a própria Microsoft incluiu

um item com o histórico de modificações desde a versão 2000. Assim, para poupar

trabalho, utilizei o que já estava pronto. Isto se chama reutilização, lembra-se? ;)

Resolvi apresentar apenas as modificações nos objetos mais utilizados pela maioria dos

desenvolvedores, ou seja, apenas serão exibidas as alterações nos objetos mais

conhecidos. Você poderá ver a lista completa de modificações acessando a

documentação da ajuda do editor do VBA do Access 2007.

AccessObject

Propriedades Status

FullName

Alterado

Sintaxe anterior

READ-ONLY FullName [STRING]

Nova sintaxe

READ-WRITE FullName [STRING]

Type

Alterado

Sintaxe anterior

READ-ONLY Type [INT32]

Nova sintaxe

READ-ONLY Type [ACOBJECTTYPE]

AcCommand

Page 128: ACCESS 2010_Classes.pdf

128

Propriedades Status

acCmdDataAccessPageBrowse Oculto

acCmdDataAccessPageDesignView Oculto

acCmdDemote Oculto

acCmdImport Oculto

acCmdMicrosoftScriptEditor Oculto

acCmdNewObjectDataAccessPage Oculto

acCmdPromote Oculto

acCmdPublish Removido

acCmdSaveAsASP Oculto

acCmdSaveAsDataAccessPage Oculto

acCmdSaveAsIDC Oculto

acCmdSelectDataAccessPage Oculto

acCmdShowOnlyWebToolbar Oculto

acCmdStopLoadingPage Oculto

acCmdViewDataAccessPages Oculto

Application

Propriedades Status

CurrentObjectType

Alterado

Sintaxe anterior

READ-ONLY CurrentObjectType [INT32]

Nova sintaxe

READ-ONLY CurrentObjectType [ACOBJECTTYPE]

DataAccessPages Oculto

DefaultWebOptions Oculto

FileSearch Oculto

Métodos Status

CreateControl

Alterado

Sintaxe anteriorr

CONTROL CreateControl (STRING FormName, ACCONTROLTYPE

ControlType, OPTIONAL ACSECTION Section = 0, OPTIONAL

VARIANT Parent, OPTIONAL VARIANT ColumnName, OPTIONAL

VARIANT Left, OPTIONAL VARIANT Top, OPTIONAL VARIANT

Width, OPTIONAL VARIANT Height)

Nova sintaxe

Page 129: ACCESS 2010_Classes.pdf

129

_CONTROL CreateControl (STRING FormName, ACCONTROLTYPE

ControlType, OPTIONAL ACSECTION Section = 0, OPTIONAL

VARIANT Parent, OPTIONAL VARIANT ColumnName, OPTIONAL

VARIANT Left, OPTIONAL VARIANT Top, OPTIONAL VARIANT

Width, OPTIONAL VARIANT Height)

CreateDataAccessPage Oculto

CreateReportControl

Alterado

Sintaxe anterior

CONTROL CreateReportControl (STRING ReportName,

ACCONTROLTYPE ControlType, OPTIONAL ACSECTION Section = 0,

OPTIONAL VARIANT Parent, OPTIONAL VARIANT ColumnName,

OPTIONAL VARIANT Left, OPTIONAL VARIANT Top, OPTIONAL

VARIANT Width, OPTIONAL VARIANT Height)

Nova sintaxe

_CONTROL CreateReportControl (STRING ReportName,

ACCONTROLTYPE ControlType, OPTIONAL ACSECTION Section = 0,

OPTIONAL VARIANT Parent, OPTIONAL VARIANT ColumnName,

OPTIONAL VARIANT Left, OPTIONAL VARIANT Top, OPTIONAL

VARIANT Width, OPTIONAL VARIANT Height)

NewCurrentDatabase

Alterado

Sintaxe anterior

VOID NewCurrentDatabase (STRING filepath)

Nova sintaxe

VOID NewCurrentDatabase (STRING filepath, OPTIONAL

ACNEWDATABASEFORMAT FileFormat = 0, OPTIONAL VARIANT

Template, OPTIONAL STRING SiteAddress = "", OPTIONAL STRING

ListID = "")

OpenCurrentDatabase

Alterado

Sintaxe anterior

VOID OpenCurrentDatabase (STRING filepath, OPTIONAL BOOL

Exclusive = 0)

Nova sintaxe

VOID OpenCurrentDatabase (STRING filepath, OPTIONAL BOOL

Exclusive = 0, OPTIONAL STRING bstrPassword = "")

Page 130: ACCESS 2010_Classes.pdf

130

ComboBox

Propriedades Status

AllowedText Oculto

DoCmd

Propriedades Status

ApplyFilter

Alterado

Sintaxe anterior

VOID ApplyFilter (OPTIONAL VARIANT FilterName,

OPTIONAL VARIANT WhereCondition)

Nova sintaxe

VOID ApplyFilter (OPTIONAL VARIANT FilterName,

OPTIONAL VARIANT WhereCondition, OPTIONAL VARIANT

ControlName)

OpenReport

Alterado

Sintaxe anterior

VOID OpenReport (VARIANT ReportName, OPTIONAL

ACVIEW View = 0, OPTIONAL VARIANT FilterName,

OPTIONAL VARIANT WhereCondition)

Nova sintaxe

VOID OpenReport (VARIANT ReportName, OPTIONAL

ACVIEW View = 0, OPTIONAL VARIANT FilterName,

OPTIONAL VARIANT WhereCondition, OPTIONAL

ACWINDOWMODE WindowMode = 0, OPTIONAL VARIANT

OpenArgs)

OutputTo

Alterado

Sintaxe anterior

VOID OutputTo (ACOUTPUTOBJECTTYPE ObjectType,

OPTIONAL VARIANT ObjectName, OPTIONAL VARIANT

OutputFormat, OPTIONAL VARIANT OutputFile, OPTIONAL

VARIANT AutoStart, OPTIONAL VARIANT TemplateFile)

Nova sintaxe

VOID OutputTo (ACOUTPUTOBJECTTYPE ObjectType,

Page 131: ACCESS 2010_Classes.pdf

131

OPTIONAL VARIANT ObjectName, OPTIONAL VARIANT

OutputFormat, OPTIONAL VARIANT OutputFile, OPTIONAL

VARIANT AutoStart, OPTIONAL VARIANT TemplateFile,

OPTIONAL VARIANT Encoding, OPTIONAL

ACEXPORTQUALITY OutputQuality = 0) ;

SelectObject

Alterado

Sintaxe anterior

VOID SelectObject (ACOBJECTTYPE ObjectType, OPTIONAL

VARIANT ObjectName, OPTIONAL VARIANT

InDatabaseWindow)

Nova sintaxe

VOID SelectObject (ACOBJECTTYPE ObjectType, OPTIONAL

VARIANT ObjectName, OPTIONAL VARIANT

InNavigationPane)

TransferSpreadsheet

Alterado

Sintaxe anterior

VOID TransferSpreadsheet (OPTIONAL

ACDATATRANSFERTYPE TransferType = 0, OPTIONAL

ACSPREADSHEETTYPE SpreadsheetType = 8, OPTIONAL

VARIANT TableName, OPTIONAL VARIANT FileName,

OPTIONAL VARIANT HasFieldNames, OPTIONAL VARIANT

Range, OPTIONAL VARIANT UseOA)

Nova sintaxe

VOID TransferSpreadsheet (OPTIONAL

ACDATATRANSFERTYPE TransferType = 0, OPTIONAL

ACSPREADSHEETTYPE SpreadsheetType = 10, OPTIONAL

VARIANT TableName, OPTIONAL VARIANT FileName,

OPTIONAL VARIANT HasFieldNames, OPTIONAL VARIANT

Range, OPTIONAL VARIANT UseOA)

Form

Propriedades Status

AllowDesignChanges Oculto

Section

Alterado

Sintaxe anterior

READ-ONLY Section [SECTION] (VARIANT Index)

Page 132: ACCESS 2010_Classes.pdf

132

Nova sintaxe

READ-ONLY Section [_SECTION] (VARIANT Index)

WhatsThisButton Oculto

ListBox

Propriedades Status

TextAlign Oculto

Report

Propriedades Status

Section

Alterado

Sintaxe anterior

READ-ONLY Section [SECTION] (VARIANT Index)

Nova sintaxe

READ-ONLY Section [_SECTION] (VARIANT Index)

TextBox

Propriedades Status

AllowedText Oculto

FELineBreak Oculto

Access em 64 bits

Uma das mudanças mais importantes que aconteceu recentemente foi o suporte para

aplicativos em 64 bits. Isto denota a chegada irremediável do futuro do

desenvolvimento. Hoje estamos vivendo uma época de transição em que aplicativos de

32 e 64 bits convivem lado a lado, deixando confusos tanto usuários quanto

desenvolvedores.

Porém, em um futuro próximo, as aplicações de 32 bits estarão obsoletas, assim como

as aplicações de 16 bits ainda existentes hoje. Então porque esperar para aprender sobre

Page 133: ACCESS 2010_Classes.pdf

133

esta novidade? Veja o tutorial feito também pelo amigo Avelino Sampaio sobre as

alteraçães necessárias para programar VBA em 64 bits:

http://usandoaccess.com.br/tutoriais/tuto28.asp?id=1#inicio

Atualizando o Conhecimento

Para quem está interessado em se manter atualizado com as novas tecnologias,

conceitos e tudo mais que cerca o desenvolvimento com as ferramentas do Office, o

principal ponto de referência é o próprio site da Microsoft para desenvolvedores. O

MSDN é o local onde se encontra toda a documentação sobre os aplicativos, as API´s e

as dicas da comunidade. Visite o site e veja quanta informação está disponível:

http://msdn.microsoft.com/pt-br/default.aspx

No entanto, há vários outros locais para se buscar o conhecimento. Na maioria dos sites

sobre o assunto você encontrará artigos, tutoriais e exemplos, além dos fóruns em que

participantes mais experientes geralmente tiram as dúvidas dos iniciantes, além das

próprias dúvidas ao trocar experiências com outros membros. Estes são alguns dos

principais:

Em Português:

www.usandoaccess.com.br

www.expertaccess.com.br

www.ativoaccess.com.br

www.juliobattisti.com.br

www.apostilando.com

www.imasters.com.br/secao/access

comunidade.itlab.com.br

www.scriptbrasil.com.br

www.linhadecodigo.com.br/access.aspx

www.marcoratti.net

Em Inglês:

www.mvps.org/access

www.lebans.com

www.functionx.com/vbaccess/index.htm

Page 134: ACCESS 2010_Classes.pdf

134

www.blueclaw-db.com/accessvisualbasic

www.excel-vba.com/excel-vba-contents.htm

www.allenbrowne.com/tips.html

Além de participar de fóruns e pesquisar em sites, além da própria ajuda do Access, é

extremamente importante ler bons livros sobre o assunto. Procure saber mais sobre

orientação a objetos, sobre acesso a dados, modelagem de banco de dados e padrões de

projeto.

Seu aperfeiçoamento depende agora exclusivamente de você. Eu ficaria muito feliz em

saber que você decidiu se tornar um desenvolvedor especialista no assunto incentivado

pelo que aprendeu nestes artigos. E ficaria mais feliz ainda se soubesse que você está

disseminando este conhecimento para outros interessados.

Chegamos ao Fim

Enfim chegamos ao final da série. Foi uma longa jornada em que tive que pesquisar,

estudar e planejar meu tempo, buscando janelas de horários em que pudesse me dedicar

a escrever os artigos, enquanto outras tarefas aguardavam ansiosas para seram também

continuadas.

A todos que esperaram com entusiasmo o lançamento de cada um dos artigos peço

desculpas pela demora no intervalo entre cada publicação, pois como devem imaginar

tudo foi feito nas horas vagas, inclusive finais de semana e feriados.

A todos que acompanharam a série um muitíssimo obrigado. Tenho certeza de que as

lições foram capazes de proporcionar o conhecimento mínimo necessário para que

desenvolvam projetos orientados a objeto com qualidade.

Espero nos encontrarmos em breve em mais um trabalho tão quanto ou mais gratificante

que este.

Abraços e até a próxima!

Fonte: http://www.mabesi.com/busca-avancada.html?searchword=CLASSES&searchphrase=all