Ir para o conteúdo
  • Cursos
  • Sobre
  • Conteúdo
  • Eventos
  • Contato
Menu
  • Cursos
  • Sobre
  • Conteúdo
  • Eventos
  • Contato
pedir orçamento
BLOG

VBA – Artigo 029 – Usando formulários com classe – parte 1: classe

Usando formulários com classe – parte 1: classe

O título deste artigo tem duplo sentido de forma intencional. Aqui
veremos como usar formulários com classe usando classes. Se você ainda não
leu o artigo sobre classes ou quer revisá-lo antes de continuar, segue o
link. Usar classes é fazer uso do que a programação orientada a objetos tem
de melhor.

Antes de mais nada, é preciso entender como projetar para que esse
processo seja usado de forma eficiente. Precisamos definir a função de
cada um: o que o formulário fará, o que a classe fará e quem vai se
comunicar com quem. A imagem abaixo deixa isso de forma mais clara:


Através da imagem vemos que a classe fará a ponte entre o formulário e a
planilha. Quais as vantagens de ser feito dessa forma?  Em primeiro
lugar, o principal objetivo da programação orientada a objetos é
reaproveitamento de código. Uma classe bem estruturada pode ser
reaproveitada em outras partes do projeto ou em outros projetos. Um
formulário se comunicando diretamente com a planilha dificilmente será
reaproveitável. Já a classe poderá ser reaproveitada com pequenas
alterações. Uma outra vantagem de usar classes é que você pode fazer a
consistência de valores nela própria, não no formulário, mantendo assim
toda a inteligência em um só lugar e aumentando a quantidade de código que
poderá ser reaproveitado com a classe.

Suponha um exemplo onde você tem uma planilha com dados de clientes,
fornecedores e funcionários. Em todos os casos teremos código, nome,
documento de identificação (CPF/CNPJ) e mais alguns dados específicos de
cada um. Os métodos e funções de cada classe provavelmente serão os
mesmos: adicionar, pesquisar, alterar e desativar (exclusão lógica; bem
melhor que exclusão física – explicarei mais adiante). Ao fazer uma classe
com suas propriedades e métodos comunicando com a respectiva planilha você
pode replicar boa parte do código para as outras classes, bastando
alterar, adicionar ou remover algumas propriedades e refletindo essas
alterações nos métodos e funções. Depois basta desenvolver o novo
formulário e criar suas ligações com a respectiva classe. Além disso, há a
possibilidade de testar a classe com sub-rotinas de teste, sem ter o
formulário ainda pronto.

No caso de fazer um formulário comunicando diretamente com a planilha até
dá para copiar o formulário e fazer as devidas alterações, mas será
preciso muita atenção. O problema é que as pessoas acabam dando muita
atenção à aparência primeiro e depois pensando na funcionalidade. Com uma
classe específica pronta e devidamente testada, basta fazer as conexões do
formulário com essa classe, sem muita necessidade de código no formulário,
pois a maior parte das funcionalidades está na classe. Os eventos do
formulário basicamente chamarão os métodos e as funções da classe ou
definirão os valores de suas propriedades.

Vamos usar um exemplo simples de um formulário de funcionários, onde
temos as seguintes propriedades: número registro do funcionário, nome
completo, data de nascimento, CPF, cargo e salário. A planilha terá o nome
Funcionários e o nome de código (codename)
PlFuncionarios. Se não entendeu ou não sabe onde definir esses
nomes, veja a imagem abaixo, é autoexplicativa:


Com o nome de código definido temos a vantagem de não precisar usar uma
variável do tipo Sheet para fazer a referência à planilha. Além
disso, caso o usuário renomeie a planilha (o nome que aparece para ele no
Excel) o funcionamento não sofrerá interferência, já que a referência será
feita via codename.

Crie a planilha e faça o cabeçalho, conforme a imagem abaixo:


Em seguida, crie um módulo de classe chamado clsFuncionario e
acrescente o seguinte código das propriedades:
Private pRegistro       As
Long    
        ‘ Registro do
funcionário
Private
pNome           As
String           ‘
Nome completo
Private pDataNascimento As Date    
        ‘ Data de
nascimento
Private
pCPF           
As String * 11      ‘ CPF
Private pCargo          As Integer 
        ‘ Código do cargo
Private pSalario        As
Currency         ‘ Salário
Private pAtivo         
As Boolean          ‘
Indicador de ativo
Private pInconsistencia As Boolean 
        ‘ Indicador de dado
inconsistente

Private pLinha          As
Long    
        ‘ Ponteiro de linha para
PlFuncionarios

‘ Registro: somente leitura

Public Property Get Registro() As Long
    Registro = pRegistro
End Property
‘ Nome: leitura e escrita
Public Property Get Nome() As String
    Nome = pNome
End Property
Public Property Let Nome(Valor As String)
    pNome = Valor
    pInconsistencia = False
End Property
‘ DataNascimento: leitura e escrita
Public Property Get DataNascimento() As Date
    DataNascimento = pDataNascimento
End Property
Public Property Let DataNascimento(Valor As Date)
    pDataNascimento = Valor
    pInconsistencia = False
End Property
‘ CPF: leitura e escrita
Public Property Get CPF() As String
    CPF = pCPF
End Property
Public Property Let CPF(Valor As String)
    Valor = Trim(Replace(Replace(Valor, “.”, “”), “-“,
“”))

    If Len(Valor) < 11 Then
        Valor = String(11 – Len(Valor), “0”) &
Valor

    End If
    If ValidarCPF(Valor) Then
        pCPF = Valor
        pInconsistencia = False
    Else
        pCPF = 0
        pInconsistencia = True
    End If
End Property
‘ Funcao: leitura e escrita
Public Property Get Cargo() As Integer
    Cargo = pCargo
End Property
Public Property Let Cargo(Valor As Integer)
    If Valor > 0 Then
        pCargo = Valor
        pInconsistencia = False
    Else
        pCargo = 0
        pInconsistencia = True
    End If
End Property
‘ Salario: leitura e escrita
Public Property Get Salario() As Currency
    Salario = pSalario
End Property
Public Property Let Salario(Valor As Currency)
    If Valor > 0 Then
        pSalario = Valor
        pInconsistencia = False
    Else
        pSalario = 0
        pInconsistencia = True
    End If
End Property
‘ Ativo: somente leitura
Public Property Get Ativo() As Boolean
    Ativo = pAtivo
End Property
‘ Inconsistencia: somente leitura
Public Property Get Inconsistencia() As Long
    Inconsistencia = pInconsistencia
End Property
Caso você tenha lido (ou relido) o artigo sobre classes deve entender
todo o código (ou pelo menos uma boa parte). Se fez uma análise entre o
enunciado e o código, percebeu que acrescentei duas propriedades booleanas
somente leitura chamadas Ativo e Inconsistencia:

– Ativo, como o nome diz, servirá para dizer se o registro está
ativo. Quando essa propriedade valer verdadeiro significa que o
registro pode ser usado sem problemas, quando valer falso significa
que não pode ser usada porque foi “excluída”. Isso é uma exclusão lógica,
ou seja, o registro está inativo e não deve ser utilizado. Exclusões
físicas de dados costumam dar muita dor de cabeça para recuperar os dados
porque sempre haverá algum usuário agindo como tal. A exclusão lógica
previne que um registro seja de fato apagado, podendo aparecer em
históricos e até mesmo ser recuperado, bastando alterar o status desta
propriedade;

– Inconsistencia servirá para indicar ao formulário (ou qualquer
outro objeto que instancie essa classe) que o valor enviado para a
propriedade é inválido e não foi armazenado. Perceba que a variável
pInconsistencia é atualizada em todas as Property Let,
mantendo essa propriedade atualizada sempre que um novo valor for
associado a alguma propriedade da classe. Nas propriedades que há
validação de dados pInconsistencia pode receber
verdadeiro ou falso, nas que não há validação recebe apenas
falso para não interferir alguma checagem dessa propriedade mal
colocada.



As propriedades Cargo e Salario validam se recebem valores positivos diferentes de zero, caso contrário
ligam o indicador de inconsistência. Já
 Nome e DataNascimento apenas guardam o dado, sem efetuar consistências.


Note que a propriedade CPF
está como uma string de 11 dígitos. Uma variável do tipo
long armazena até 2.147.483.647, ou seja, não consegue armazenar
todos os 11 dígitos. Na escrita (Let) é primeiro removido eventuais
pontos e hífens, depois o conteúdo é transformado em 11 dígitos se
necessário e por fim é enviado para a 
função ValidarCPF, que
primeiramente deve checar se o valor recebido é numérico antes de conferir
se o DAC é válido para o número.


A propriedade Registro é somente leitura, ou seja, não podemos
associar um valor diretamente à propriedade. Como é que vamos definir um
valor novo? Através de uma função chamada Pesquisa. Essa função,
como o próprio nome entrega, fará a pesquisa na tabela pelo
Registro, recebendo o valor na função e retornando
verdadeiro ou falso. Se verdadeiro, também carrega os
valores em suas respectivas propriedades. 
Ao contrário do que possa parecer, essa forma é feita para simplificar.
Imagine que devêssemos definir o valor de
Registro
e depois executar a função
Pesquisa:
Funcionario.Registro = txtRegistro.Value
Funcionario.Pesquisar
Colocando o Registro como parâmetro na função
Pesquisar reduz uma linha:
Funcionario.Pesquisar(txtRegistro.Value)
Essa função Pesquisar deverá saber o intervalo atual da tabela de
funcionários, guardar o número do registro (fornecido como parâmetro) na
propriedade Registro da classe e pesquisar essa coluna para saber
se o valor existe na base. Se existir, irá armazenar o número da linha em
pLinha e compor as propriedades com seus respectivos valores, além
de retornar o valor verdadeiro. Caso não exista, o valor de
pLinha será o número da última linha mais um, já preparando a
classe para adicionar um eventual novo registro e retornará falso.
Compreendido o funcionamento da função, segue o código:
Public Function Pesquisar(Registro As Long) As Boolean
    Dim UltimaLinha As Long
    Dim Intervalo   As Range
    Dim Encontrado  As Range
    Dim NumCPF      As String
    pRegistro = Registro
    PlFuncionarios.Activate
    UltimaLinha = PlFuncionarios.Cells.Find(“*”,
LookIn:=xlFormulas, _
        SearchOrder:=xlByRows,
SearchDirection:=xlPrevious).Row
    Set Intervalo = PlFuncionarios.Range(Cells(1, 1),
Cells(UltimaLinha, 1))
    Set Encontrado = Intervalo.Find(pRegistro,
LookIn:=xlFormulas, _
        LookAt:=xlWhole,
SearchOrder:=xlByColumns)
    If Encontrado Is Nothing Then
        plinha = UltimaLinha + 1
        Pesquisar = False
    Else
        pLinha = Encontrado.Row
        pNome =
PlFuncionarios.Cells(pLinha, 2).Value
        pDataNascimento =
PlFuncionarios.Cells(pLinha, 3).Value
        NumCPF = PlFuncionarios.Cells(pLinha, 4).Value
        If Len(NumCPF) < 11 Then
            pCPF = String(11 –
Len(NumCPF), “0”) & NumCPF

        Else
            pCPF = NumCPF
        End If

        pCargo = PlFuncionarios.Cells(pLinha, 5).Value

        pSalario =
PlFuncionarios.Cells(pLinha, 6).Value
        pAtivo =
PlFuncionarios.Cells(pLinha, 7).Value
        Pesquisar = True
    End If
End Function
Você pode testar a função incluindo um funcionário manualmente e criando
uma rotina de teste que exiba os dados quando encontrado ou exiba uma
mensagem quando não encontrado. Pode fazer essa rotina como um
exercício
, vale a pena testar uma função ou método de classe tão logo esteja
pronto.



Veja que é na pesquisa que leremos o valor do CPF, que é armazenado como
número na planilha e, portanto, o Excel remove os zeros à esquerda. Para
trazer o número com 11 dígitos é preciso fazer a verificação que está na
rotina e preencher os zeros conforme a necessidade.

As outras funcionalidades precisarão que Pesquisar tenha sido executada, para os valores de Registro e pLinha estejam
devidamente preenchidos. Caso contrário, é possível que
pLinha tenha valor zero e uma mensagem de erro surgirá ao tentar
acessar a linha zero da planilha, que não existe. Para prevenir isso,
vamos criar uma função privada que retornará verdadeiro quando os
valores sejam positivos e diferentes de zero, caso contrário retornará
falso:
Private Function ValidarPosicao() As Boolean
    If pRegistro >= 0 And pLinha >= 0 Then
        ValidarPosicao = True
    Else
        ValidarPosicao = False
    End If
End Function
Note que essa função é privada, ou seja, somente será acessada
internamente pela própria classe. Podemos então passar às outras
funcionalidades. Poderíamos construir como métodos, que não retornam
valores, mas vamos podemos construir como funções, retornando
verdadeiro para indicar que processou conforme o esperado e
falso para indicar que não processou por algum problema, como a
função ValidarPosicao retornando falso (afinal, é para isso
mesmo que ela foi criada). Segue o código dessas funções:
Public Function Adicionar() As Boolean
    If ValidarPosicao = False Then
        Adicionar = False
    Else
        PlFuncionarios.Cells(pLinha,
1).Value = pRegistro
        PlFuncionarios.Cells(pLinha,
2).Value = pNome
        PlFuncionarios.Cells(pLinha,
3).Value = pDataNascimento
        PlFuncionarios.Cells(pLinha,
4).Value = pCPF
        PlFuncionarios.Cells(pLinha,
5).Value = p
Cargo
        PlFuncionarios.Cells(pLinha,
6).Value = pSalario
        PlFuncionarios.Cells(pLinha,
7).Value = True
        Adicionar = True
    End If
End Function
Public Function Alterar() As Boolean
    If ValidarPosicao = False Then
        Alterar = False
    Else
        PlFuncionarios.Cells(pLinha,
2).Value = pNome
        PlFuncionarios.Cells(pLinha,
3).Value = pDataNascimento
        PlFuncionarios.Cells(pLinha,
4).Value = pCPF
        PlFuncionarios.Cells(pLinha,
5).Value = p
Cargo
        PlFuncionarios.Cells(pLinha,
6).Value = pSalario
        Alterar = True
    End If
End Function
Public Function Ativar() As Boolean
    If ValidarPosicao = False Then
        Ativar = False
    Else
        PlFuncionarios.Cells(pLinha,
7).Value = True
        Ativar = True
    End If
End Function
Public Function Desativar() As Boolean
    If ValidarPosicao = False Then
        Desativar = False
    Else
        PlFuncionarios.Cells(pLinha,
7).Value = False
        Desativar = True
    End If
End Function
Crie as rotinas de teste para as funções acima como exercício, colocando
em um módulo exclusivo para esse fim. Ponha um nome como
TesteClasseFuncionario. Tenha o hábito de sempre testar cada método
ou função logo após ter codificado, isso garante que você testará com a
lógica ainda fresca na cabeça, permitindo encontrar eventuais erros mais
facilmente. Também recomendo manter o módulo de testes, para testar
eventuais alterações futuras no código ou mesmo para ter rotinas de teste
prontas quando replicar a classe em outro lugar.
.
Perceba que não inclui ainda a função ValidarCPF e por isso dará
erro ao tentar associar um valor à propriedade CPF. Você pode
codificar essa parte  como exercício (a forma de calcular o DAC é
facilmente encontrado na internet) antes de seguir adiante. Você
também exercitar criando um método privado para ordenar a tabela e
chamá-lo no final da função Adicionar
. Os códigos seguem abaixo, mas tente fazer como exercício antes:


Function ValidarCPF(CPF As String) As Boolean
    If IsNumeric(CPF) Then
        If Len(CPF) < 11
Then
           
CPF = String(11 – Len(CPF), “0”) & CPF
        End If
        If Right$(CPF, 2) =
CalcularDAC(CPF) Then
           
ValidarCPF = True
        Else
           
ValidarCPF = False
        End If
    Else
        ValidarCPF = False
    End If
End Function
Private Function CalcularDAC(CPF As String) As String
    Dim Soma    As Integer
    Dim Resto   As Integer
    Dim DAC1    As Integer
    Dim DAC2    As Integer
    Soma = 10 * CInt(Left(CPF, 1)) + 9 * CInt(Mid(CPF,
2, 1)) + 8 * _
        CInt(Mid(CPF, 3, 1)) + 7 * CInt(Mid(CPF, 4, 1)) + 6 * _
        CInt(Mid(CPF, 5, 1)) + 5 * CInt(Mid(CPF, 6,
1)) 
+ 4 * _
        CInt(Mid(CPF, 7, 1)) + 3 * CInt(Mid(CPF, 8,
1)) + 2 * _
        CInt(Mid(CPF, 9, 1))
    Resto = Soma Mod 11
    If Resto = 0 Or Resto = 1 Then
        DAC1 = 0
    Else
        DAC1 = 11 – Resto
    End If
    Soma = 11 * CInt(Left(CPF, 1)) + 10 *
CInt(Mid(CPF, 2, 1)) + 9 * _
        CInt(Mid(CPF, 3, 1)) + 8 * CInt(Mid(CPF, 4, 1)) + 7 * _
        CInt(Mid(CPF, 5, 1)) + 6 * CInt(Mid(CPF, 6,
1)) 
+ 5 * _
        CInt(Mid(CPF, 7, 1)) + 4 * CInt(Mid(CPF, 8,
1)) + 3 * _
        CInt(Mid(CPF, 9, 1)) + 2 * DAC1
    Resto = Soma Mod 11
    If Resto = 0 Or Resto = 1 Then
        DAC2 = 0
    Else
        DAC2 = 11 – Resto
    End If
    CalcularDAC = CStr(DAC1) & CStr(DAC2)
End Function
Private Sub OrdenarTabela()
    Dim UltimaLinha As Long
    Dim Intervalo As Range
    PlFuncionarios.Activate
    UltimaLinha = PlFuncionarios.Cells.Find(“*”,
LookIn:=xlFormulas, _

        SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
    Set Intervalo = PlFuncionarios.Range(Cells(1, 1),
Cells(UltimaLinha, 7))

    With PlFuncionarios.Sort
        .SortFields.Clear
        .SortFields.Add
Range(“A1”)
        .Header = xlYes
        .SetRange Intervalo
        .Apply
    End With

End Sub


Até aqui vimos apenas a classe, que aparentemente está pronta – se você exercitou e
fez as rotinas mencionadas acima. A parte do formulário segue em um artigo
à parte para não deixar este tão extenso e para facilitar a consulta
quando necessário (se quiser informação sobre classe vem aqui, se quiser
sobre formulário vai no outro).

Para dúvidas sobre o artigo, comentários ou sugestões, utilize os
comentários abaixo. Até o próximo artigo!


Pedro Martins

Pós-graduando em Business Intelligence e Big Data pela Faculdade
Impacta de Tecnologia. Formado em Tecnologia em Eletrônica Digital com
Ênfase em Microprocessadores
Catálogo de aulas (NOVIDADE)

Criei um catálogo de aulas para ajudar você em seus estudos. Acesse clicando na imagem abaixo ou clique aqui.

Contato

Telefone:

+55 11 98861.4882

E-mail:

contato@alessandrotrovato.com.br

Siga-nos

Facebook Instagram Linkedin Twitter Youtube

© Copyright 2024 – Todos os direitos reservados | Alessandro Trovato

criado por: