A função VLOOKUP (PROCV em Português) é uma função muito interessante e muito utilizada pois permite procurar por um valor numa tabela/matriz e devolver o valor que está na coluna ou na coluna à direita, indicando-se para isso o índice. Existe também a função HLOOKUP (PROCH em Português) para pesquisas na horizontal.
Para quem nunca utilizou, este é o sintaxe da função:
=VLOOKUP(valor procurar; tabela; coluna a devolver; resultado aproximado)
Mas vejamos um exemplo simples para mostrar como funciona a função VLOOKUP.

Como podem ver na imagem anterior temos uma tabela com duas colunas. Na coluna A temos a selecção, utilizando um ‘x’ (podíamos procurar por número, ID, etc.) e na coluna B temos nomes de B2 a B9. Se quisermos procurar o nome que está selecionado podíamos usar a seguinte função:
=VLOOKUP("x";A2:B9;2;FALSE)
O resultado na célula onde colocássemos a função seria “Paulo”
Breve descrição dos argumentos:
- O primeiro argumento (x) indica o valor a procurar;
- O segundo argumento (A2:B9) indica a matriz, sendo a coluna da esquerda a coluna onde vamos procurar os valores (neste caso a coluna A);
- O terceiro argumento (2) indica a coluna de onde será devolvido o valor. Neste caso vamos devolver o valor que está na coluna B (2ª coluna), e por isso indicamos o valor 2, mas se tivéssemos mais colunas, por exemplo números de telefone na coluna C, poderíamos indicar como valor 3 e modificar o segundo argumento de A2:B9 para A2:C9.
- O quarto argumento (FALSE) indica que não queremos resultados aproximados mas sim exactos
Mas por muito interessante e útil que a função seja só nos devolve um resultado, ou seja, se selecionar dois ou três nomes, apenas irá devolver o primeiro que encontrar.
Usando VBA podemos resolver esta “limitação” e devolver múltiplos resultados de acordo com as selecção. Para isso podemos criar um novo módulo e utilizar o seguinte código:
Public Function VLookupValues(lookupValue As String, _
lookupRange As Range, _
columnIndex As Integer, _
Optional distinct As Boolean = False) _
As String
Dim x As Long
Dim result As String
On Error GoTo errVLookupValues
' Ciclo em todas as linhas do range
For x = 1 To lookupRange.Rows.Count
Dim r As Range
Set r = lookupRange.Cells(x, 1)
' Verifica se o valor é igual ao indicado
If r.Value = lookupValue Then
Dim str As String
' Utiliza o Offset para ir buscar a coluna indicada
str = r.Offset(, columnIndex - 1).Value & ";"
' Caso se pretenda apenas os valores diferentes e
' já esteja já na lista não faz a concatenação
If distinct And InStr(1, result, str, vbTextCompare) = 0 _
Or Not distinct Then
result = result & str
End If
End If
Next
' Se não encontrar nada coloca uma mensagem genérica
If Len(result) > 0 Then
' Remove o último ";"
VLookupValues = Left(result, Len(result) - 1)
Else
VLookupValues = "Não Encontrado"
End If
Exit Function
errVLookupValues:
VLookupValues = ""
End Function
Para tornar a função mais versátil foi adicionado um argumento opcional que permite indicar se queremos resultados únicos ou não. O sintaxe para utilizar esta função é o seguinte:
=vLookupValues(valor procurar; tabela; coluna a devolver; resultados únicos)
E utilizando a mesma tabela agora com várias selecções:

Se utilizarmos a função =VLookupValues("x";A2:B9;2;FALSE), em qualquer célula, obtemos o resultado: Rui;Ana;Paulo;Paula
Podemos ainda indicar no último argumento se queremos ou não resultado únicos.
Podem descarregar um exemplo para testar!
No primeiro artigo sobre a personalização do friso (ribbon) foi mostrado como criar um novo separador e um novo grupo com dois controlos, neste caso, dois botões.
Mas podemos utilizar inúmeros controlos de modo a tornar as opções mais simples para o utilizador. Como referido também no artigo anterior, este é o esquema base para construção do friso:
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
<ribbon startFromScratch="false">
<tabs>
<tab id="customTab1" label="Extra Options">
<!-- Grupos, Controlos, etc -->
</tab>
</tabs>
</ribbon>
</customUI>
O próximo código XML apresentado irá ser colocado dentro da tab com o ID “customTab1”
Vamos ver então alguns controlos, alguns eventos, designados por callbacks, e algumas opções mais avançadas!

Para criar um grupo com caixas de selecção (checkboxes), no primeiro grupo (myCheckBox Group), podemos o fazer da seguinte forma:
<group id="Group1" label="myCheckBox Group">
<checkBox id="cb1" label="Opção A" onAction="cbGetDescription" />
<checkBox id="cb2" label="Opção B" onAction="cbGetDescription" />
<checkBox id="cb3" label="Opção C" onAction="cbGetDescription" />
<checkBox id="cb4" label="Opção D" onAction="cbGetDescription" />
<checkBox id="cb5" label="Opção E" enabled="false" />
<checkBox id="cb6" label="Opção F" enabled="false" />
</group>

Neste caso estamos a criar um grupo, onde vamos ter várias checkboxes (6). As primeiras quatro estão a chamar o callback cbGetDescription, onde irmos depois verificar qual a opção selecionada, e as duas últimas estão desabilitadas para efeitos de demonstração.
No callback (evento) cbGetDescription podemos usar o seguinte código:
Sub cbGetDescription(control As IRibbonControl, pressed As Boolean)
Select Case control.id
Case "cb1"
MsgBox "Opção A - Seleccionada: " & pressed
Case "cb2"
MsgBox "Opção B - Seleccionada: " & pressed
Case "cb3"
MsgBox "Opção C - Seleccionada: " & pressed
Case "cb4"
MsgBox "Opção D - Seleccionada: " & pressed
End Select
End Sub
No segundo grupo (MyDrops Group) estão dois controlos de selecção: Combobox e DropDown. A diferença entre ambos é que na Combobox é possível alterar o texto enquanto na DropDown não. Neste exemplo, e para mostrar diferentes formas de carregamento de dados, na Combobox estão já definidos alguns itens e a DropDown será preenchida dinamicamente com dados de um Array definido no código.
O XML para a sua criação será então o seguinte:
<group id="Group2" label="myDrops Group">
<comboBox id="cboItems" label="ComboBox:" onChange="cboOnChange">
<item id="item1" label="Item 1" />
<item id="item2" label="Item 2" />
<item id="item3" label="Item 3" />
</comboBox>
<dropDown id="dropDynamic" label="Dropdown:"
onAction="ddOnAction"
getItemLabel="ddGetItemLabel"
getItemCount ="ddGetItemCount" >
</dropDown>
</group>
Como código para a Combobox podemos definir então:
Sub cboOnChange(control As IRibbonControl, text As String)
MsgBox "Texto seleccionado: " & text
End Sub
Isto irá mostrar uma mensagem com o texto seleccionado ou inserido.
Para a DropDown o código é ligeiramente mais complexo!
Para começar vamos adicionar na primeira linha do XML o atributo onLoad definindo desta forma que quando o friso é iniciado iremos executar determinado código (poderia ser feito também no evento Workbook_Open).
Desta forma vamos executar o callback RibbonLoad() na inicialização do friso, onde iremos carregar alguns valores no array. Estes valores vão ser utilizados pelos métodos GetItemLabel() e GetItemCount() como é possível ver no seguinte código/comentários.
Private paises(4) As String
Private x As Integer
Sub RibbonLoad(ribbon As IRibbonUI)
paises(0) = "Portugal"
paises(1) = "Espanha"
paises(2) = "França"
paises(3) = "Alemanha"
paises(4) = "Inglaterra"
End Sub
' Mostra a determinada posição do array de acordo com o índex recebido
Sub ddOnAction(control As IRibbonControl, id As String, index As Integer)
MsgBox paises(index), vbInformation
End Sub
' Este evento é chamado uma vez por cada posição na lista, definido no
' evento ddGetItemCount(). Desta forma, quando o evento é executado, colocamos
' um valor de cada posição do array e incrementamos o contador de posição
Sub ddGetItemLabel(control As IRibbonControl, index As Integer, ByRef returnedVal)
returnedVal = paises(x)
x = x + 1
End Sub
' Define o número de itens a aparecer na lista
Sub ddGetItemCount(control As IRibbonControl, ByRef returnedVal)
returnedVal = UBound(paises) + 1
End Sub
O terceiro e último grupo (myMisc Group) tem diferentes controlos para mostrar mais algumas das possibilidades disponíveis (não todas, obviamente). O XML é um pouco extenso mas será explicado de seguida:
<group id="Group3" label="myMisc Group">
<gallery id="MonthGallery" label="Escolher mês usando uma Gallery:"
columns="3" rows="4" onAction="SetMonth" >
<item id="m01" label="Janeiro"/>
<item id="m02" label="Fevereiro"/>
<item id="m03" label="Março"/>
<item id="m04" label="Abril"/>
<item id="m05" label="Maio"/>
<item id="m06" label="Junho"/>
<item id="m07" label="Julho"/>
<item id="m08" label="Agosto"/>
<item id="m09" label="Setembro"/>
<item id="m10" label="Outubro"/>
<item id="m11" label="Novembro"/>
<item id="m12" label="Dezembro"/>
<button id="mActual" imageMso="CalendarToolSelectDate"
label="Mês Actual" onAction="SetCurrentMonth" />
</gallery>
<editBox id="EditBox1" label="Texto a pesquisar:" onChange="EditBoxOnChange"
imageMso="FindAllDownloadedDocuments" />
<separator id="separator1"/>
<toggleButton id="toggleActivar" label="Activar/Desactivar"
imageMso="AcceptTask" getPressed="toggleGetPressed"
onAction="toggleOnAction" />
<menu id="Menu1" label="Menu Opções Sistema" itemSize="normal">
<button idMso="Cut"/>
<button idMso="Copy"/>
<button idMso="Paste"/>
<menuSeparator id="menuSeparator1" title="Mais opções ..."/>
<menu id="SubMenu1" label="Ficheiro">
<button idMso="FileSave"/>
<button idMso="FileSaveAs"/>
<button idMso="FileOpen"/>
<button idMso="FileClose"/>
</menu>
<menu id="SubMenu2" label="Diversos">
<button idMso="FileExit"/>
</menu>
</menu>
<dialogBoxLauncher>
<button id="Launcher1" screentip="My Launcher"
onAction="ThisWorkbook.LauncherCode" />
</dialogBoxLauncher>
</group>
Para começar uma galeria (Gallery) onde estamos a definir os diferentes meses do ano. Aqui podemos indicar quantas linhas e colunas queremos, assim como utilizar outros controlos. No código XML está definido no final um botão que irá escolher o mês actual.

O código associado é muito simples:
' Mostra o mês de acordo com o index recebido
Sub SetMonth(control As IRibbonControl, id As String, index As Integer)
MsgBox MonthName(index + 1)
End Sub
' Mostra o mês por extenso do mês actual
Sub SetCurrentMonth(control As IRibbonControl)
MsgBox MonthName(Month(Now))
End Sub
De seguida temos uma EditBox que permite o utilizador escrever algum texto. No código basta simplesmente mostrar o resultado no callback EditBoxOnChange():
Sub EditBoxOnChange(control As IRibbonControl, text As String)
MsgBox "O texto indicado foi: " & text, vbInformation
End Sub
Depois um separador e um botão retentivo (toggle button), ou seja, quando pressionado fica seleccionado e quando pressionado novamente perde a selecção.

No código do toggle button mostramos apenas o estado no callback onAction() e definimos também, no callback getPressed(), o estado inicial quando o friso é inicializado.
' Quando o botão (toggle) é pressionado mostra o estado
Sub toggleOnAction(control As IRibbonControl, pressed As Boolean)
MsgBox "Controlo: " & control.id & " - Pressionado: " & pressed
End Sub
' Define o estado inicial do botão
Sub toggleGetPressed(control As IRibbonControl, ByRef returnedVal)
returnedVal = True
End Sub
Depois, no próximo controlo utilizado, não existe qualquer código associado pois estamos a definir funções de sistema através da atribuição de um idMso. Isto significa que cada opção que colocarmos no menu, que poderá ser colocado em outro controlo, irá executar a função que o sistema está preparado para o fazer (save, save as, copy, cut, etc).
Desta forma, podemos colocar no nosso friso algumas opções já existentes no Excel e que podem ser úteis. A lista dos ID’s (idMso) que podemos utilizar pode ser descarregada aqui:
O último controlo, embora meio escondido e disponível no canto inferior direito do grupo, é um DialogBox Launcher que permite simplesmente lançar uma janela com opções relaccionadas com o respectivo grupo.

O código pode então mostrar uma mensagem, chamar um userform, etc. Neste exemplo irá mostrar apenas uma mensagem, mas tem uma particularidade, que se aplica a todos os controlos. No XML está definido para o callback onAction() o método ThisWorkbook.LauncherCode. Isto significa que o seguinte código tem de estar localizado no ThisWorkbook para funcionar, pois está a ser apontado para tal.
Sub LauncherCode(control As IRibbonControl)
MsgBox "Mais opções ..."
End Sub
Podemos apontar para módulos específicos, worksheets, etc.
NOTA IMPORTANTE: Caso o XML não esta correcto (tags inválidas, tags não fechadas, etc) o separador não ficará visível.
E são alguns exemplos que mostram como personalizar o friso e como utilizar o código para cada controlo. Existem muito mais opções para cada controlo e muito mais controlos. Para complementar estes dois pequenos artigos podem ver os seguintes links, que além de um PDF que podem descarregar gratuitamente, podem consultar online:
Podem ainda descarregar o ficheiro de exemplo utilizado neste artigo: download