VBA - Artigo 007 - Tratando entradas em formulários


Tratando entradas em formulários


Como você deve saber, podemos usar caixas de texto em formulários para digitação, que são muito úteis para obter dados pelo usuário. Porém, muitas vezes também precisamos impor restrições, para que a entrada do usuário não seja inválida e possa gerar erros no código.

O usuário pode, por exemplo, colocar espaços em branco antes ou depois do texto. Isto pode ser um problema, por exemplo, quando for preciso comparar a entrada com um dado existente, a fim de evitar duplicidade de dados. Assim sendo, é uma boa prática sempre usar o método Trim quando receber entradas do usuário. Veja o exemplo abaixo:

Private Sub txtNome_Exit(ByVal Cancel As MSForms.ReturnBoolean)

    Debug.Print "[" & frmCadastro.txtNome & "]"
    frmCadastro.txtNome = Trim(frmCadastro.txtNome)
    Debug.Print "[" & frmCadastro.txtNome & "]"

End Sub

O evento Exit atuará quando o cursor sair da caixa de texto txtNome. Executando um teste colocando "   Fulano   " (três espaços de cada lado), teremos a seguinte saída na Verificação imediata:

[   Fulano   ]
[Fulano]

A primeira linha exibe o texto recebido entre colchetes (colocados aqui apenas para melhor visualizar os espaços extras) e a segunda linha mostra o resultado após usar o Trim. Porém, o usuário também pode colocar espaços a mais entre as palavras da entrada. Neste caso, será necessário deixar o código um pouco mais sofisticado:

Private Sub txtNome_Exit(ByVal Cancel As MSForms.ReturnBoolean)

    Debug.Print "[" & frmCadastro.txtNome & "]"
    frmCadastro.txtNome = Trim(frmCadastro.txtNome)
    Do While InStr(frmCadastro.txtNome, "  ")
        frmCadastro.txtNome = Replace(frmCadastro.txtNome, "  ", " ")
    Loop
    Debug.Print "[" & frmCadastro.txtNome & "]"

End Sub

Aqui usei uma estrutura de repetição para verificar se há dois espaços consecutivos. Se não houver, nem entrará na estrutura. Se houver, ele executará a ação de substituir dois espaços por um até que não haja mais ocorrências. Veja um exemplo da execução desse código:

[ Fulano  de    tal ]
[Fulano de tal]

Dependendo da necessidade, pode-se utilizar também os métodos UCase e LCase caso precise que a entrada seja toda em maiúsculas ou minúsculas, respectivamente.

É possível estipular um limite de caracteres em uma entrada.  Isso é feito utilizando a propriedade MaxLength da caixa de texto. Pode ser feito diretamente nas propriedades do objeto no formulário ou via código:

frmCadastro.txtNome.MaxLength = 25

Este comando definirá o limite de 25 caracteres para a caixa de texto txtNome, sendo a melhor forma de cumprir um limite de tamanho, pois o usuário não conseguirá digitar além dessa quantidade. Use quando houver restrição de espaço. Em campos de nome provavelmente não haverá restrição, mas há outros casos em que é necessário.

Você pode preferir alterar nas propriedades do formulário, mas há casos em que pode ser necessário fazer isso via código. Por exemplo, você tem um campo que pode receber o número de CPF ou CNPJ. Neste caso, você precisará também de botões de opção para selecionar se é pessoa física ou jurídica e, com base nessa seleção, estipular se o limite de caracteres será 11 ou 14. Observe o código a seguir:

Private Sub optFisica_Click()

    txtCPFCNPJ.Enabled = True
    txtCPFCNPJ.MaxLength = 11
    txtCPFCNPJ.SetFocus

End Sub

Private Sub optJuridica_Click()

    txtCPFCNPJ.Enabled = True
    txtCPFCNPJ.MaxLength = 14
    txtCPFCNPJ.SetFocus

End Sub

Assim que o usuário clicar em uma das opções, a caixa de texto txtCPFCNPJ será habilitada, terá o tamanho máximo definido e receberá o foco do cursor. Note que para funcionar adequadamente a propriedade Enabled de txtCPFCNPJ deve ser definida como False por padrão, evitando que entre no campo sem selecionar o tipo de pessoa antes.

Para ficar melhor ainda, podemos restringir a digitação apenas a números, evitando que o usuário digite letras, sinais de pontuação ou outros símbolos. Para isso precisamos editar o evento KeyPress da caixa de texto, que trata exatamente disso:

Private Sub txtCPFCNPJ_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)

    Select Case KeyAscii
        Case Asc("0") To Asc("9")
        Case Else
            KeyAscii = 0
    End Select

End Sub

Esse evento traz um parâmetro KeyAscii, que representa o caractere digitado. Só precisamos validar o que está sendo recebido e permitir ou não o valor digitado. Asc permite que você possa usar a própria representação do caractere entre aspas ao invés do código associado ao caractere. É bem mais fácil entender Case Asc("0") To Asc("9") do que Case 48 To 57, certo? Perceba que não há nenhuma instrução após essa linha, logo em seguida vem Case Else. Mesmo sem instrução, o Excel vai sair do Select Case e vai prosseguir quando se o caractere digitado estiver entre 0 e 9. Qualquer outro caractere que for digitado entrará no Case Else, que irá descartar esse caractere.

Perceba que você pode permitir outros caracteres, adicionando um Case antes do Case Else. Assim você pode permitir traços, pontos, parênteses etc quando for preciso. Mas o usuário poderá digitar em posições erradas, o que vai comprometer a integridade do dado. Há uma forma melhor de colocar pontos, traços etc quando eles são fixos. Vejamos este exemplo de caixa de texto para telefone:

Private Sub txtTelefone_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)

    txtTelefone.MaxLength = 13

    Select Case KeyAscii
        Case Asc("0") To Asc("9")
            If txtTelefone.SelStart = 0 Then
                txtTelefone.SelText = "("
            ElseIf txtTelefone.SelStart = 3 Then
                txtTelefone.SelText = ")"
            ElseIf txtTelefone.SelStart = 8 Then
                txtTelefone.SelText = "-"
            End If
        Case Else
            KeyAscii = 0
    End Select

End Sub

Note que foi acrescentado um bloco If que atuará quando for digitado um número. A propriedade SelStart é um índice, determina a posição do texto onde o cursor está. Fique atento que o índice inicia em zero. SelText irá acrescentar um caractere na posição se for o caso. Há ainda a propriedade SelLength, que trata do comprimento do texto selecionado, mas não precisamos usá-lo aqui. Experimente o código e veja como fica muito prático deixar a própria caixa de texto colocando os parênteses e o traço do número de telefone. Note que o limite está em 13 caracteres, para números de celular com 9 dígitos é preciso aumentar o limite e alterar a posição do hífen.

E se quisermos fazer o mesmo com o nosso campo de CPF/CNPJ do exemplo anterior? Podemos melhorar o código, codificando a mesma validação para as posições de cada um. Neste exemplo vou ainda acrescentar uma enumeração (se não conhece veja meu artigo 6) para determinar o tipo de pessoa:

Enum enumPessoa
    Fisica = 0
    Juridica = 1
End Enum
Private Pessoa As enumPessoa

Private Sub optFisica_Click()

    Pessoa = Fisica
    txtCPFCNPJ.Enabled = True
    txtCPFCNPJ.MaxLength = 14
    txtCPFCNPJ.Value = ""
    txtCPFCNPJ.SetFocus

End Sub

Private Sub optJuridica_Click()

    Pessoa = Juridica
    txtCPFCNPJ.Enabled = True
    txtCPFCNPJ.MaxLength = 18
    txtCPFCNPJ.Value = ""
    txtCPFCNPJ.SetFocus

End Sub

Private Sub txtCPFCNPJ_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)

    Select Case KeyAscii
        Case Asc("0") To Asc("9")
            Select Case Pessoa
                Case Fisica
                    If txtCPFCNPJ.SelStart = 3 Or txtCPFCNPJ.SelStart = 7 Then
                        txtCPFCNPJ.SelText = "."
                    ElseIf txtCPFCNPJ.SelStart = 11 Then
                        txtCPFCNPJ.SelText = "-"
                    End If
                Case Juridica
                    If txtCPFCNPJ.SelStart = 2 Or txtCPFCNPJ.SelStart = 6 Then
                        txtCPFCNPJ.SelText = "."
                    ElseIf txtCPFCNPJ.SelStart = 10 Then
                        txtCPFCNPJ.SelText = "/"
                    ElseIf txtCPFCNPJ.SelStart = 15 Then
                        txtCPFCNPJ.SelText = "-"
                    End If
            End Select
        Case Else
            KeyAscii = 0
    End Select

End Sub

Alterei as rotinas de seleção de opção para definir o objeto Pessoa, bem como esvaziar o campo txtCPFCNPJ quando a seleção for trocada, porque senão os caracteres separadores permanecerão nas posições anteriores e acaba gerando uma confusão. Se o usuário digitar alguns números e depois voltar para o começo para acrescentar algum zero, os pontos não irão ficar no lugar. Assim, o usuário pode deixar os dados com problemas. Para sanar isso temos duas alternativas: verificar e atualizar enquanto digita o dado, o que é muito complexo e trabalhoso, ou verificar após o cursor sair da caixa de texto. Esta opção parece mais fácil de fazer. Analise o código abaixo:

Private Sub txtCPFCNPJ_Exit(ByVal Cancel As MSForms.ReturnBoolean)

    If Len(txtCPFCNPJ) > 0 Then
        Select Case Pessoa
            Case Fisica
                If Len(txtCPFCNPJ) < 14 Or Mid(txtCPFCNPJ, 4, 1) <> "." Or _
                   Mid(txtCPFCNPJ, 8, 1) <> "." Or Mid(txtCPFCNPJ, 11, 1) <> "-" Then
                   txtCPFCNPJ = Trim(Replace(Replace(Replace(txtCPFCNPJ.Value, _
                       ".", ""), "-", ""), "/", ""))
                   txtCPFCNPJ = String(11 - Len(txtCPFCNPJ), "0") & txtCPFCNPJ
                   txtCPFCNPJ = Left(txtCPFCNPJ, 3) & "." & Mid(txtCPFCNPJ, 4, 3) & _
                       "." & Mid(txtCPFCNPJ, 7, 3) & "-" & Right(txtCPFCNPJ, 2)
                End If
            Case Juridica
                If Len(txtCPFCNPJ) < 18 Or Mid(txtCPFCNPJ, 3, 1) <> "." Or _
                   Mid(txtCPFCNPJ, 7, 1) <> "." Or Mid(txtCPFCNPJ, 11, 1) <> "/" Or _
                   Mid(txtCPFCNPJ, 16, 1) <> "-" Then
                   txtCPFCNPJ = Trim(Replace(Replace(Replace(txtCPFCNPJ.Value, _
                       ".", ""), "-", ""), "/", ""))
                   txtCPFCNPJ = String(14 - Len(txtCPFCNPJ), "0") & txtCPFCNPJ
                   txtCPFCNPJ = Left(txtCPFCNPJ, 2) & "." & Mid(txtCPFCNPJ, 3, 3) & _
                       "." & Mid(txtCPFCNPJ, 6, 3) & "/" & Mid(txtCPFCNPJ, 9, 4) & _
                       "-" & Right(txtCPFCNPJ, 2)
                End If
        End Select
    End If

End Sub

Aqui utilizamos o evento Exit da caixa de texto txtCPFCNPJ, que executa logo que o cursor sai da caixa de texto. A primeira validação serve para verificar se há conteúdo, se algum número foi digitado. Se nada foi digitado, nada acontece e o campo continua vazio. Se algo foi digitado, é verificado se a pessoa é física ou jurídica, para  verificar se o comprimento está no limite e se os separadores estão nas posições corretas. Caso isso haja algo errado, o número é reformatado, tirando os símbolos não numéricos e depois recompondo os separadores nas posições corretas.

Experimente o código pronto e sinta-se livre para usá-lo em algum formulário já existente. Pratique outras formas também, use o código como inspiração para outros modelos existentes.

Adendo:

O Excel tem um bug quando recebe datas pelo formulário. Acontece muito de datas como 04/12 serem transformadas em 12/04. Aparentemente, ele considera datas mm/dd/yyyy a menos que o mm seja maior do que 12, quando considera como dd/mm/yyyy. A solução que encontrei é usar DateValue() para converter a data apropriadamente. Esse comando deve ser usado quando você estiver trazendo o valor do campo do formulário, como no exemplo abaixo:

    DataNascimento = DateValue(txtDataNascimento.Text)

Espero ter contribuído.

Pedro Martins

Formado em Tecnologia em Eletrônica Digital, já trabalhou como artefinalista, eletrotécnico, programador de CLP (para máquinas industriais) e analista de sistemas em sistema bancário, programando em COBOL.
Mexe com computadores e programação desde a segunda metade dos anos 1980, quando teve um MSX e aprendeu a programar em BASIC. É a favor da disseminação do conhecimento.

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