VBA - Artigo 036 - Reaproveitando validações em formulários

capa do artigo com foto do Pedro, o autor e o título da postagem

Reaproveitando validações em formulários


Em artigos anteriores certamente você deve ter visto rotinas de validações de dados nos formulários. Esses códigos estavam sempre atrelados ao próprio controle do formulário, como boa parte dos desenvolvedores praticam.

Entretanto, caso você tenha vários campos similares, o código ficará repetido em vários pontos do formulário. Isso pode ser resolvido criando uma sub-rotina no formulário e fazendo os campos chamarem essa sub-rotina. Porém, se você tiver vários formulários, essa solução não funcionaria e teria duas opções: copiar o código para o outro formulário (o que duplicaria o código) ou colocar o código em um módulo à parte, de forma que seria acessível aos diversos formulários. Esta seria uma melhor opção.

Vejamos um exemplo simples, onde precisamos remover espaços adicionais de campos de nomes. É um procedimento que deve ser colocado em campos de nomes de usuários, de clientes, de fornecedores, de produtos, de marcas etc. Resumindo, é uma tarefa corriqueira que será repetida em praticamente todos os formulários. Podemos criar uma função que arrume esse texto de maneira bem simples:

Function EspacosArrumados(Texto As String)
    EspacosArrumados = Trim(Texto)
    Do While InStr(EspacosArrumados, "  ")
        EspacosArrumados = Replace(EspacosArrumados, "  ", " ")
    Loop
End Function

Essa função será usada da seguinte forma:

Private Sub txtNome_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    frmCadastro.txtNome = EspacosArrumados(frmCadastro.txtNome)
End Sub

Essa função certamente atenderá muitas necessidades. Podemos ainda aperfeiçoar a função, acrescentando um parâmetro adicional para o caso de querer que o texto seja convertido em maiúsculas, minúsculas ou iniciais maiúsculas e o resto em minúsculas, evitando que essa codificação seja feita no módulo do formulário. Esse parâmetro pode vir na forma de enumeração:

Enum enumConversao
    Nenhuma = 0
    Maiuscula = 1
    Minuscula = 2
    IniciaisMaiusculas = 3
    PrimeiraMaiuscula = 4
End Enum
Function EspacosArrumados(Texto As String, _
    Optional Conversao As enumConversao = Nenhuma) As String
    EspacosArrumados = Trim(Texto)
    Do While InStr(EspacosArrumados, "  ")
        EspacosArrumados = Replace(EspacosArrumados, "  ", " ")
    Loop
    Select Case Conversao
        Case Maiuscula
            EspacosArrumados = UCase(EspacosArrumados)
        Case Minuscula
            EspacosArrumados = LCase(EspacosArrumados)
        Case IniciaisMaiusculas
            EspacosArrumados = StrConv(EspacosArrumados, vbProperCase)
        Case PrimeiraMaiuscula
            EspacosArrumados = UCase(Left$(EspacosArrumados, 1)) & _
                LCase(Mid$(EspacosArrumados, 2, Len(EspacosArrumados) - 1))
    End Select
End Function

O parâmetro Conversao foi criado como opcional, usando a opção Nenhuma como padrão. Assim, se o campo não precisar de conversão basta não acrescentar o parâmetro.

O mesmo processo pode ser utilizado para campos com formatos específicos, como datas. Neste caso temos duas abordagens: quando o número está sendo digitado e quando sai do campo. O segundo caso é mais simples, pois apenas efetua uma validação de data, podendo inclusive verificar se a data é passada ou futura, de acordo com a necessidade. Esta abordagem será vista mais adiante.

Quando vamos formatar um campo numérico pelo próprio módulo do formulário, o código normalmente é algo assim:

Private Sub txtDataNascimento_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    Select Case KeyAscii
        Case Asc("0") To Asc("9")
            If Me.txtDataNascimento.SelStart = 2 Or Me.txtDataNascimento.SelStart = 5 _
                Then
                Me.txtDataNascimento.SelText = "/"
            End If
        Case Else
            KeyAscii = 0
    End Select
End Sub

Entretanto, para fazer o mesmo efeito em um módulo à parte é preciso fazer uma abordagem diferente. Observe o código a seguir:

Function DataFormatada(ValorAtual As String, Tecla As MSForms.ReturnInteger) As String
    Dim Digito As String
    Dim Valor As String
    Dim Comprimento As Integer
    Select Case Tecla
        Case Asc("0") To Asc("9")
            Digito = Chr$(Tecla)
        Case Else
            Digito = ""
    End Select
    Valor = Replace(ValorAtual, "/", "") & Digito
    Comprimento = Len(Valor)
    If Comprimento > 4 Then
        Valor = Left$(Valor, 2) & "/" & Mid$(Valor, 3, 2) _
            & "/" & Mid$(Valor, 5, Comprimento - 4)
    ElseIf Comprimento > 2 Then
        Valor = Left$(Valor, 2) & "/" & Mid$(Valor, 3, Comprimento - 2)
    End If
    If Len(Valor) > 10 Then
        Valor = Left$(Valor, 10)
    End If
    DataFormatada = Valor
End Function

A função recebe dois parâmetros: ValorAtual e Tecla. ValorAtual será o conteúdo atual do campo de data que recebe um novo dígito, enquanto Tecla é o caractere recebido. No começo há um Select Case para verificar se Tecla é numérico ou não. Caso positivo, armazena na variável Digito. Depois a variável Valor recebe o conteúdo do parâmetro ValorAtual sem as barras separadoras da data. Mais adiante Comprimento recebe o tamanho do texto de Valor, que recebe as barras separadoras de acordo com o tamanho. Por fim há ainda uma validação para ver se o comprimento final passou de 10, limitando Valor aos 10 primeiros dígitos.

Agora podemos substituir o código do evento de pressionamento de tecla para que o campo receba o conteúdo da função. Em tese, precisaríamos de apenas uma linha de código, mas há uma segunda. Observe:

Private Sub txtDataNascimento_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    Me.txtDataNascimento.Value = DataFormatada(Me.txtDataNascimento.Value, KeyAscii)
    KeyAscii = 0
End Sub

Lembre-se que a sub-rotina se refere a um evento e que a variável KeyAscii é o caractere digitado. Se não houver nenhum tratamento nessa variável, seu conteúdo é acrescentado ao final do campo. Por isso devemos associar o valor 0 para que o caractere digitado não seja duplicado.

A validação da data normalmente é efetuada quando saímos do campo. Vamos criar uma função que receba dois parâmetros: a data a ser validada e uma enumeração que indique se a data que queremos validar é passado, futuro ou tanto faz, pois datas de nascimento devem pertencer ao passado, assim como novas datas de pagamento devem pertencer ao futuro. Vejamos:

Enum enumPeriodoData
    Nenhum = 0
    Passado = 1
    Futuro = 2
End Enum
Function DataValidada(ValorData As String, _
    Optional PeriodoData As enumPeriodoData = Nenhum) As Boolean
    If Not IsDate(ValorData) Then
        DataValidada = False
        Exit Function
    End If
    Select Case PeriodoData
        Case Nenhum
            DataValidada = True
        Case Passado
            If CDate(ValorData) < Now Then
                DataValidada = True
            Else
                DataValidada = False
            End If
        Case Futuro
            If CDate(ValorData) > Now Then
                DataValidada = True
            Else
                DataValidada = False
            End If
    End Select
End Function

Perceba que esta função só indicará se a data é válida ou não a partir dos parâmetros recebidos. Não indicará se o erro é uma data inválida ou se ela está fora do intervalo exigido para o campo. Neste caso o ideal é ter uma variável Mensagem onde possamos escrever uma mensagem de erro para ser exibida no formulário. Nos casos em que não houver erro será preciso apagar a mensagem para que não exiba uma mensagem antiga. Entretanto, será preciso que essa variável Mensagem seja pública, para poder ser acessada por todo o projeto. Uma alternativa mais elegante é transformar todo o módulo com as validações de dados para um módulo de classe, que servirá como um repositório de funções de validação de dados.

Comece seu módulo validador de dados com uma ou duas funções e vá substituindo as existentes de um projeto, verificando se o funcionamento está normal e nenhum bug apareceu. Com o tempo, vai acrescentando mais algumas funções e fazendo o mesmo, até o momento em que todas suas validações estejam presentes no módulo. Assim, quando for iniciar algum projeto novo, importe esse módulo validador e uma boa parte do seu trabalho já estará pronta, bastando usar as funções existentes, testadas e aprovadas em projetos anteriores.

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.


Postagem Anterior Próxima Postagem