Classes no VBA
quando tiver bastante tempo para ler e praticar os códigos de exemplo.
Há muitos conceitos aqui e pode levar um tempo para absorver tudo. Leia
e releia quantas vezes for necessário e use os comentários do blog se
houver necessidade.
(POO). Embora há quem diga que o VBA não seja totalmente orientado a
objetos, a falta de alguns conceitos de POO não impede de realizar ótimos
trabalhos. A classe serve para projetar um objeto, conceito principal
da POO. É preciso enfatizar o fato que a classe é um
projeto do objeto, ou seja, a classe só é utilizada para criar (ou
instanciar) os objetos.
Inserir/Módulo de classe. É nesse módulo que você criará as
propriedades e os métodos. Ao criar um módulo de classe, a primeira coisa a
fazer é alterar a propriedade (Name) para um nome mais apropriado do
que Classe1, como por exemplo clsProduto. É boa prática
colocar o prefixo cls para diferenciar a classe dos objetos que serão
criados a partir dela. A criação do objeto é feita da seguinte maneira:
Option Explicit), enquanto a segunda efetua a criação do objeto.
Somente a partir da criação de um objeto que é possível utilizar as
propriedades e os métodos da classe que serviu de origem. Do jeito que está,
o objeto Produto não tem utilidade nenhuma, pois não tem nenhuma
propriedade ou método.
as seguintes linhas no módulo clsProduto:
seja, só serão acessadas internamente nesse módulo. Também foi adicionado um
prefixo p de propriedade. Você pode definir o prefixo que
quiser, desde que fique fácil de distinguir o que será usado só pela classe
e o que será acessado pelo objeto.
conseguir acessá-las e torná-las úteis de fato. Precisamos declarar
procedimentos que permitam esse acesso. Para isso temos de criar
Property Get e Property Let para cada propriedade. Vejamos
como fica a propriedade Nome:
para armazenar um valor na propriedade. Com este código já é possível
acessar a propriedade Nome. Atente bem ao tipo do objeto nas
declarações, que precisam combinar como tipo da propriedade. Da mesma forma,
perceba que a declaração dos procedimentos é pública, para que
possamos acessar. Se fosse declarado como privados a propriedade
seria interna do objeto e só acessada pelos próprios procedimentos do módulo
de classe. Não estranhe, há casos em que é necessário fazer dessa forma,
como veremos mais adiante.
propriedade Nome com o seguinte código:
procedimentos, entrando em Property Let para armazenar o valor e
depois entrando em Property Get para obter o conteúdo da
propriedade.
procedimentos como outros, sendo possível incluir uma consistência dos dados
enviados antes de armazenar. Veja a propriedade Quantidade abaixo:
Description:=”A quantidade não pode ser negativa”
valor caso seja maior ou igual a zero. Isso impede que nosso objeto tenha
quantidade negativa. Caso venha um valor inválido, um erro é gerado com
Err.Raise. Caso não conheça ou não entenda este método, visite meu
décimo segundo artigo, que explica o objeto Err.
e depure, depois altere o valor para negativo e veja o que acontece:
Produto.Quantidade
Preco é bem similar à Quantidade, também precisando de uma
validação para impedir números negativos. Neste caso também vamos impedir o
valor 0:
Description:=”O preço deve ser um valor positivo”
necessidade de consistência. Porém, se quisermos controlar o código, não
devemos permitir que procedimentos externos modifiquem o valor. Desta forma,
Property Let deverá ser declarada como private, ou seja, só o
próprio módulo de classe poderá modificar esta propriedade:
TesteClasse irá receber uma mensagem de erro, alertando que esse
componente não existe. Desta forma impedimos que o seja associado um valor
que possa quebrar a ordem desejada ou até repetir um valor existente. A
propriedade Codigo foi criada como somente leitura, ou seja,
só podemos ler o valor, não modificar. É possível criar propriedades
somente escrita, neste caso Property Get deverá ser
privado enquanto Property Let deverá ser público.
que momento precisamos gerar um número novo para um produto? Somente quando
for criar um novo. Portanto, o procedimento de adicionar produto deverá
buscar o último valor utilizado, incrementar 1 e definir esse valor como o
código do novo produto. Isso será feito mais adiante.
foi “excluído” ou não. Usaremos essa propriedade como uma
exclusão lógica, ou seja, a linha não será removida da tabela, apenas
constará como um produto inativo. Imagine que tenha orçamentos existentes
mencionando um determinado produto e então o apagamos da tabela: perderemos
os vínculos de dados nos orçamentos e também toda a integridade de dados,
levando a erros imprevisíveis. Por isso, é preferível fazer uma exclusão
lógica (marcar como inativo) ao invés de física (apagar a linha do produto
definitivamente). Como essa propriedade não deve ser acessada diretamente,
apenas por procedimentos, teremos Property Get e
Property Let declarados como privados:
métodos. Mas antes, criaremos uma planilha para colocar os
produtos. Crie uma planilha Produtos
e renomeie o valor da propriedade (Name) para plProdutos. Se não souber como fazer isso veja meu terceiro artigo. Crie um cabeçalho para os dados: Código, Nome, Quantidade, Preço e Ativo. Em seguida, entre no Gerenciador de nomes (tecla de atalho Ctrl + F3) e crie uma área nomeada dinâmica chamada tbProdutos
com a seguinte fórmula:
quantidade mínima de linhas seja 1, o que impede de acontecer erros por não
ter nenhuma linha com produto.
Há dois métodos de classe especiais: Class_Initialize
e Class_Terminate. Como os próprios nomes sugerem, eles se
referem à inicialização e à finalização da classe, respectivamente. Na
inicialização podemos definir valores iniciais a uma classe. Poderíamos
definir um valor inicial para as propriedades, mas não iremos usar esses
métodos neste artigo. Acrescente o procedimento a seguir no final do módulo da classe:
Set Produtos = plProdutos.Range(“tbProdutos”)
do cabeçalho
Produtos.Cells(Produtos.Rows.Count, 1).Value + 1
acrescente o código a seguir:
ao adicionar ele será sempre Verdadeiro (não faz muito sentido
incluir um produto inativo). Depure esse código, acompanhando cada passo do
processo. Veja como os valores das propriedades são adicionados e lidos.
Observe como grava uma linha na tabela. Repita o processo algumas vezes para
acrescentar algumas linhas, veja como incrementa o código. Remova algumas
linhas e acrescente mais para ver o resultado.
das linhas pode gerar duplicidade de código. Por isso é preciso de um
procedimento que ordene a tabela de produtos antes de incluir um novo.
Podemos criar esse procedimento na própria classe como private, para
que somente a própria classe execute. Adicione esta rotina no módulo da
classe:
1), _
Order:=xlAscending, DataOption:=xlSortNormal
xlTopToBottom
Adicionar, logo após a declaração de variáveis, desta forma:
OrdenarTabela
verá que o método Adicionar passa a ordenar a tabela antes de
acrescentar um produto novo a lista, impedindo o uso de um código já
existente.
existe na tabela, obtendo os valores do produto caso positivo ou deixando
tudo em branco caso contrário. Veja o código abaixo:
sempre positivo
1).Value = Valor Then
= Produtos.Cells(Linha, 1).Value
Produtos.Cells(Linha, 2).Value
Quantidade = Produtos.Cells(Linha, 3).Value
= Produtos.Cells(Linha, 4).Value
= Produtos.Cells(Linha, 5).Value
For
validação da pesquisa. A estrutura de repetição começa com valor 2 porque a primeira linha do
intervalo tbProdutos é o cabeçalho. Podemos criar um procedimento
para testar o funcionamento da pesquisa. Coloque o código abaixo no módulo
de teste:
Produto.Codigo & ” não foi encontrado”
Produto.Codigo
Produto.Nome
& Produto.Quantidade
Produto.Preco
área de Verificação imediata mostrará se o produto existe ou não na
tabela. Caso exista, mostrará os valores das propriedades, caso contrário
dará uma mensagem informativa.
propriedades, podemos localizar o código e atualizar o restante das
propriedades com os valores atuais. Vejamos:
1).Value = Valor Then
Produtos.Cells(Linha, 2).Value = Nome
Produtos.Cells(Linha, 3).Value = Quantidade
Produtos.Cells(Linha, 4).Value = Preco
For
atualizamos o mesmo produto para que a tabela reflita as alterações
desejadas. Depure para compreender o funcionamento.
1).Value = Valor Then
Produtos.Cells(Linha, 5).Value = False
Encontrado = True
For
Description:=”Produto não encontrado”
célula Ativo para Falso. Se o produto não for encontrado uma
mensagem de erro aparecerá. Podemos testar o código com outro procedimento
de teste:
código não existente para ver a mensagem de erro. Se houver necessidade
pode-se criar um método para reativar um produto, o que você deve fazer com
muita facilidade.
Como utilizar essa classe que foi criada? Imagine um formulário de
produtos, onde podemos criar, consultar, alterar e excluir produtos. Os
eventos dos botões, onde estaria toda a lógica, pode fazer uma consistência
dos dados (conferir se os dados essenciais estão preenchidos e se são
válidos) para então chamar o método da classe que efetiva o cadastro ou a
alteração na tabela de produtos. Em um outro formulário que for preciso
obter o dado de algum produto, bastaria chamar o método da classe, sem
necessidade de replicar o código que estaria no formulário de
produtos.
As classes servem para encapsular um objeto e manter toda a inteligência
acerca dele. No início pode parecer um pouco complicado trabalhar com classes, mas com o
tempo você verá que pode facilitar muito a longo prazo. Da mesma forma que
formulários, módulos de classe podem ser exportados para ser importados por
outras planilhas e adaptados, com poucas alterações, demandando menos tempo do que fazer todo o trabalho de novo.
Vimos até aqui como funcionam as propriedades das classes. Utilizamos
propriedades com e sem consistência no Property Let, bem como propriedades somente leitura e totalmente privada. Criamos
métodos para adicionar, pesquisar, alterar e desativar produtos, assim como
procedimentos para testar o funcionamento da classe. Também criamos um
método privado da classe. Acredito que este conteúdo apresentado dá uma boa
base para que você possa criar suas próprias classes.
testes, de forma que você possa verificar se suas propriedades e métodos
estão funcionando adequadamente, como fiz aqui. Manter um módulo separado
para testes evita confusão com o código que será de fato usado, que deverá
estar em outro módulo. Assim que estiver tudo testado e funcionando, o
módulo de testes pode ser excluído se quiser.
classes no Excel. Diga se houve dificuldade de entender alguma coisa e se
vai começar a usar classes em projetos futuros.
Pedro Martins
artefinalista, eletrotécnico, programador de CLP (para máquinas
industriais) e analista de sistemas em sistema bancário, programando em
COBOL.
1980, quando teve um MSX e aprendeu a programar em BASIC. É a favor da
disseminação do conhecimento.