Criar um formulário de utilizador
Os formulários de utilizador são caixas de diálogo personalizadas utilizadas para recolher dados de entrada do utilizador no início de uma macro. O UserForm Builder incluído no Code VBA cria automaticamente UserForms. Os formulários de utilizador gerados têm um código de validação de entrada adicionado para garantir que todas as entradas necessárias são do tipo correto. Isto tornará a macro mais fiável. O facto de os controlos e o código de validação serem gerados poupa muito tempo que teria de despender para criar o formulário de utilizador manualmente. O UserForm pode ser alterado para tornar o design visualmente mais atrativo, movendo e redimensionando os controlos. Além disso, é possível alargar o código vba do formulário de utilizador para satisfazer requisitos adicionais.
Utilizar o UserForm Builder
O UserForm Builder é iniciado a partir do menu Código VBA:
Alt-CDUB | Menu: Code VBA " Dialog " UserForm " |

No UserForm Builder, especificará
- UserForm Name (Nome do formulário do utilizador): dê um nome ao formulário que seja curto para os dados que serão introduzidos. No exemplo, o nome é "Order" (encomenda)
-
A grelha de Controlos é a área em que especifica os controlos que pretende incluir no UserForm que está a criar.
Cada controlo é especificado numa linha separada com propriedades:
- Nome: será utilizado como etiqueta para o controlo de entrada.
- Tipo de dados: se o utilizador introduzir um valor de tipo incorreto no controlo, ao premir o botão OK, o utilizador recebe uma mensagem de que o valor desse campo está incorreto e volta a colocar o cursor nesse campo para que o utilizador o corrija.
- Tipo de controlo: permite-lhe especificar o tipo de controlo preferido. Um booleano (sim/não) pode ser representado de uma forma fácil de utilizar através de um controlo
- Obrigatório: se o utilizador não introduzir um valor no controlo, ao premir o botão OK o utilizador recebe uma mensagem a informar que falta um valor para esse campo e coloca o cursor nesse campo.
- Selecionar nomes...: abre uma janela caixa de entrada de seleção de intervalo para lhe permitir selecionar um ou mais nomes da sua folha de Excel. Isto é útil se a caixa de diálogo for criada para preencher um formulário ou tabela Excel existente.
- Create: cria o UserForm - imagem abaixo - e insere o código para iniciar o userform.

Código VBA do UserForm
Para além do objeto UserForm, o construtor também adiciona três partes de código:
- Código para abrir / mostrar o formulário do utilizador
- Tipo definido pelo utilizador
- Validação da entrada do utilizador
Código para abrir / mostrar o formulário do utilizador
Supondo que o cursor estava dentro do procedimento Sub Demo
, depois de premir OK no UserForm Builder, o procedimento teria o seguinte aspeto
Sub Demo()
Dim udtOrder As Order
With udtOrder
.Client = ""
.EntryDate = Date
.Product = ""
.Attention = True
End With
ufmOrder.FillList "cboProduct", Array("v1", "v2", "v3")
ufmOrder.SetValues udtOrder
ufmOrder.Show
If Not ufmOrder.IsCancelled Then
ufmOrder.GetValues udtOrder
''continue process after OK here
With udtOrder
End With
End If
Unload ufmOrder
End Sub
Para obter uma interface limpa, é utilizado um Tipo Definido pelo Utilizador que inclui os controlos de dados com as respectivas definições de tipo no formulário do utilizador.
Pode alterar o código entre o primeiro With
e End With
para alterar os valores iniciais ou predefinidos.
A passagem dos valores para o formulário é efectuada no método SetValues
O procedimento FillList é utilizado para passar uma matriz de valores para a caixa de listagem Product. Os valores da matriz ("v1",...) são apenas um exemplo que terá de adaptar.
O método Show
é a forma padrão de abrir o UserForm.
O utilizador pode premir OK ou Cancelar a caixa de diálogo. Isto é determinado através do teste da propriedade .IsCancelled
.
Se o utilizador tiver premido OK, a macro continuará a utilizar os dados que o utilizador forneceu no formulário do utilizador.
Para o efeito, adicionará o seu próprio código de processo entre o segundo With
e End With
.
Tipo definido pelo utilizador para uma interface limpa
O Tipo Definido pelo Utilizador gerado fornece uma interface limpa entre a sua macro e o UserForm. Se o procedimento a partir do qual está a chamar o formulário do utilizador estiver num módulo padrão, o tipo definido pelo utilizador será aí colocado. Caso contrário, será colocado num módulo chamado 'modTypes'. No exemplo, a declaração de tipo tem o seguinte aspeto:
Public Type Order
Client As String
EntryDate As Date
Product As String
Attention As Boolean
End Type
Validação do UserForm e outro código
No interior do UserForm gerado, existe ainda uma grande quantidade de código que é utilizado para:
- Manuseamento de OK e Cancelar
- Transmissão de dados para o formulário do utilizador
- Validação dos dados introduzidos
Manuseamento de OK e Cancelar
O código abaixo mostra o tratamento dos botões Ok e Cancelar. O botão Fechar também é tratado adequadamente como Cancelar sem necessidade de código adicional.
A variável pública IsCancelled
é utilizada para comunicar à macro de chamada se o utilizador premiu Ok ou Cancelar.
Public IsCancelled As Boolean
Private Sub UserForm_Initialize()
IsCancelled = True
End Sub
Private Sub btnCancel_Click()
Me.Hide
End Sub
Private Sub btnOk_Click()
If IsInputOk Then
IsCancelled = False
Me.Hide
End If
End Sub
Transmissão de dados para o formulário do utilizador
Os dados são transmitidos e obtidos a partir do formulário do utilizador através de SetValues
e GetValues
, respetivamente.
Ambos utilizam a variável Tipo definido pelo utilizador.
Public Sub SetValues(udtOrder As Order)
With udtOrder
SetValue Me.txtClient, .Client
SetValue Me.txtEntryDate, .EntryDate
SetValue Me.cboProduct, .Product
SetValue Me.cbxAttention, .Attention
End With
End Sub
Public Sub GetValues(ByRef udtOrder As Order)
With udtOrder
.Client = GetValue(Me.txtClient, TypeName(.Client))
.EntryDate = GetValue(Me.txtEntryDate, TypeName(.EntryDate))
.Product = GetValue(Me.cboProduct, TypeName(.Product))
.Attention = GetValue(Me.cbxAttention, TypeName(.Attention))
End With
End Sub
SetValues
e GetValues
são implementados utilizando os procedimentos abaixo indicados:
Private Sub SetValue(ctl As MSForms.Control, value As Variant)
On Error GoTo HandleError
ctl.value = value
HandleExit:
Exit Sub
HandleError:
Resume HandleExit
End Sub
Private Function GetValue(ctl As MSForms.Control, strTypeName As String) As Variant
On Error GoTo HandleError
Dim value As Variant
value = ctl.value
If IsNull(value) And strTypeName <> "Variant" Then
Select Case strTypeName
Case "String"
value = ""
Case Else
value = 0
End Select
End If
HandleExit:
GetValue = value
Exit Function
HandleError:
Resume HandleExit
End Function
Validar a entrada do formulário do utilizador
Quando o utilizador prime OK, os dados do UserForm são validados pela função IsInputOk
.
Esta verifica, para cada controlo de entrada IsInputControl
, se tem um valor HasValue
, caso seja necessário IsRequired
.
Em seguida, verifica se o valor é do tipo correto IsCorrectType
- tal como foi especificado no UserForm Builder.
A não aprovação em qualquer um dos testes resulta numa mensagem para o utilizador e na colocação do foco no controlo cujo valor falhou ctl.SetFocus
.
Private Function IsInputOk() As Boolean
Dim ctl As MSForms.Control
Dim strMessage As String
IsInputOk = False
For Each ctl In Me.Controls
If IsInputControl(ctl) Then
If IsRequired(ctl) Then
If Not HasValue(ctl) Then
strMessage = ControlName(ctl) & " must have value"
End If
End If
If Not IsCorrectType(ctl) Then
strMessage = ControlName(ctl) & " is not correct"
End If
End If
If Len(strMessage) > 0 Then
ctl.SetFocus
GoTo HandleMessage
End If
Next
IsInputOk = True
HandleExit:
Exit Function
HandleMessage:
MsgBox strMessage
GoTo HandleExit
End Function
Note-se que IsCorrectType
utiliza a função ControlDataType
que devolve simplesmente o tipo para o controlo dado utilizando as instruções Select Case
inseridas pelo UserForm Builder. Uma abordagem semelhante, mas mais simples, é seguida para IsRequired
.
Private Function IsCorrectType(ctl As MSForms.Control) As Boolean
Dim strControlDataType As String, strMessage As String
Dim dummy As Variant
strControlDataType = ControlDataType(ctl)
On Error GoTo HandleError
Select Case strControlDataType
Case "Boolean"
dummy = CBool(GetValue(ctl, strControlDataType))
Case "Byte"
dummy = CByte(GetValue(ctl, strControlDataType))
Case "Currency"
dummy = CCur(GetValue(ctl, strControlDataType))
Case "Date"
dummy = CDate(GetValue(ctl, strControlDataType))
Case "Double"
dummy = CDbl(GetValue(ctl, strControlDataType))
Case "Decimal"
dummy = CDec(GetValue(ctl, strControlDataType))
Case "Integer"
dummy = CInt(GetValue(ctl, strControlDataType))
Case "Long"
dummy = CLng(GetValue(ctl, strControlDataType))
Case "Single"
dummy = CSng(GetValue(ctl, strControlDataType))
Case "String"
dummy = CStr(GetValue(ctl, strControlDataType))
Case "Variant"
dummy = CVar(GetValue(ctl, strControlDataType))
End Select
IsCorrectType = True
HandleExit:
Exit Function
HandleError:
IsCorrectType = False
Resume HandleExit
End Function
Private Function ControlDataType(ctl As MSForms.Control) As String
Select Case ctl.Name
Case "txtClient": ControlDataType = "String"
Case "txtEntryDate": ControlDataType = "Date"
Case "cboProduct": ControlDataType = "String"
Case "cbxAttention": ControlDataType = "Boolean"
End Select
End Function
Private Function IsRequired(ctl As MSForms.Control) As Boolean
Select Case ctl.Name
Case "txtClient", "txtEntryDate", "cboProduct", "cbxAttention"
IsRequired = True
Case Else
IsRequired = False
End Select
End Function