... Assinatura do site por 3 anos + Kit MontaRibbons + 3 Livros em PDF + Diversas Revistas (pdf) de brinde, por apenas R$182,00
(
podendo parcelar em até 10 vezes no cartão de crédito)...

Clique aqui e obtenha mais detalhes do nosso kit completo e de como comprar.


Combobox e Dropdown, na prática

Se você acompanhou os tutoriais anteriores, já sabe que é possível alterarmos as ribbons, em tempo de execução, utilizando os atributos gets (getVisible, getEnabled, getLabel, ...).  

Agora, você aprenderá a usar os atributos gets, pertinentes aos controles Combobox e Dropdown, com o objetivo de preencher a lista, de forma dinâmica.  Serão apresentados dois exemplos práticos: 

- a montagem de uma lista de relatórios;

- a montagem de uma lista de clientes, que servirá de filtragem para um formulário.

Qual é a diferença de um controle Combobox para um controle Dropdown ?

A diferença está no fato de que no controle Combobox , podemos entrar com um valor, que esteja ou não presente na lista, o que já não é permitido no Dropdown.   E na programação há uma pequena vantagem no emprego do Combobox, por ele permitir o uso direto do valor da lista.  Já no Dropdown o valor retornado é o índice na lista.  Mas isso não é fator impeditivo de se usar o Dropdown.

Compare os dois controles no código XML: 

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="fncRibbon">

<ribbon startFromScratch="true">
<tabs>
<tab id = "guia1" label = "ComboBox e DropDown ">
<group id = "gr1" label = "ComboBox e DropDown" >

<comboBox id = "cbx1" label = "Combo dinâmico" 
getItemCount = "fncGetItemCountCbx"
getItemLabel = "fncGetItemLabelCbx"
onChange = "fncOnChangeCbx"
/>

<labelControl id = "lb1" label = "----------------------------------------------" />

<dropDown id = "dd1" label = "Drop dinâmico" 
getItemCount = "fncGetItemCountDrop"
getItemLabel = "fncGetItemLabelDrop"
onAction="fncOnActionDrop"
/>

</group>
</tab>
</tabs>
</ribbon>
</customUI>

Observe que a diferença está apenas nos atributos que executam um evento de ação.  O atributo OnAction para o Dropdown e o atributo OnChange para o controle Combobox.

Agora, veja o resultado do código XML:

Ribbons - combobox e dropdown dinâmicas

Vamos começar demonstrando a técnica de preenchimento dinâmico da lista, usando o controle Dropdown. 

Mecânica do preenchimento: o atributo getItemCount informa para o controle Dropdown a quantidade de itens que terá a lista.  O controle Dropdown usa esta informação para disparar o atributo geItemLabel o número de vezes necessárias para se obter os nomes (labels) que irão compor a lista.   

Tanto a quantidade de itens quanto os nomes que irão preencher a lista serão capturados de uma tabela. 

Observe bem os campos da tabela utilizada:

Ribbons - combobox e dropdown dinâmicas

 

O campo Descricao será usado para o preenchimento da lista.  E a ordem desta lista será controlada pelo campo idx.  

O primeiro get a ser disparado pela Dropdown é o getItemCount que irá capturar o número máximo de itens da lista e que corresponde ao número total de registros da tabela.

Observe a função fncGetItemCountDrop.

Sub fncGetItemCountDrop(control As IRibbonControl, ByRef count)
'Informa ao Dropdown, através da variável count, a quantidade de registros da 
'tabela tblListaRelatorios, que será a quantidade máxima de linhas do Dropdown.
count = DCount("*", "tblListaRelatorios")
End Sub

E para que serve o argumento Control na função acima?  É utilizado para o caso de termos mais de um controle Dropdown nas ribbons.  Veja como fica a função para se controlar mais de um Dropdown:

Sub fncGetItemCountDrop(control As IRibbonControl, ByRef count)
  Select case control.id
    case "dd1" 'Nome de um controle Dropdown
      count = DCount("*", "NomeDatabela")
    case "dd2" 'Nome de outro controle Dropdown
      'Informa ao dropdown, através da variável count, a quantidade de 
      'registros da tabela tblListaRelatorios, que será a quantidade máxima
      'de linhas do dropdown.
      count = DCount("*", "tblListaRelatorios")
  end select
End Sub

Agora que o controle Dropdown sabe da quantidade total de itens que terá a lista,  irá capturar cada um dos itens (label), através do atributo getItemLabel

Observe a função fncGetItemLabelDrop() que o get irá disparar para buscar os labels:

Sub fncGetItemlabelDrop(control As IRibbonControl, index As Integer, ByRef label)
'Informa ao Dropdown, através do argumento label, o nome do relatório armazenado
'na tabela tblListarelatorios.
'idx é um número exclusivo para cada relatório que deverá coincidir com a 
'posição(index) no Dropdown.
label = DLookup("descricao", "tblComboDinamica", "idx =" & index)
End Sub

A nossa tabela exemplo tem 4 registros, que foi o número informado para o controle Dropdown.  Este por sua vez irá passar pela função fncGetItemLabelDrop() 4 vezes.   Isso mesmo! A função será chamada a quantidade de vezes que tiver o comprimento da lista!  E cada vez que o controle passar pelo função, o argumento index será incrementado de 1 (iindex + 1). Começando sempre do zero(0). 

Assim ficou fácil carregarmos o label correspondente, bastando sincronizar o argumento index com o campo idx da tabela.

Veja a lista carregada:

Ribbons - combobox e dropdown dinâmicas

Para completar, vejamos o atributo onAction, que irá dar funcionalidade ao controle Dropdown.  A função disparada por este atributo é a fncOnActiondrop().

Sub fncOnActionDrop(control As IRibbonControl,selectedId As String,selectedIndex As Integer)
Dim strNomeRelatorio as string
'o argumento selectedIndex traz o número do item que foi selecionado pelo usuário
strNomeRelatorio = DLookup("relatorio", "tblListaRelatorios", "idx =" & selectedIndex)
DoCmd.OpenReport strNomeRelatorio, acViewPreview
'Refaz a lista, limpando assim a caixa dropdown
objRibbon.InvalidateControl ("dd1")
End Sub

O nome do relatório é capturado pela função DLookup().  Veja que capturamos o nome do relatório que corresponde ao número selectedIndex e que deverá coincidir com o campo idx.

E quanto ao controle Combox ?

Tudo igualzinho, exceto pelo atributo de chamada onChange e que fará disparar a função fncOnChangeCbx:

Sub fncOnChangeCbx(control As IRibbonControl, strText As String)
dim strNomeRelatorio as string
'O argumento strText possui o valor digitado ou selecionado do combobox.  
'Usamos este valor como filtragem da função Dlookup() para capturarmos da tabela 
'o nome exato do relatório a ser aberto.
strNomeRelatorio = dlookup("relatório","tblListaRelatorios","descricao='" & strText & "'") 
DoCmd.OpenReport strNomeRelatorio, acViewPreview
objRibbon.InvalidateControl ("cbx1")
End Sub

Este foi um caso bem simples, em que a tabela tinha um número de registros bem reduzido e com isso foi possível numerar manualmente o campo idx, que determina a ordem em que as informações do campo Descricao serão carregadas na lista do controle. 

Já para uma tabela, com uma quantidade de registros grande e dinâmica, o uso do campo idx, obviamente, se torna inviável.   A questão é resolvida de uma forma relativamente simples, que consiste em capturar os registros da tabela, ordená-los na forma desejada e armazená-los, temporariamente, na memória do computador, através do uso de uma variável do tipo Array.  Esta passagem das informações para a memória é feita na função fncGetItemCountCbx, pois ela é disparada antes da função fncGetItemLabelCbx, que carrega os nomes para a lista.

Antes de prosseguirmos , entenda um pouco sobre variáveis do tipo Arrays.

As Arrays são variáveis que consistem em uma coleção de valores, chamados elementos do Array.  Exemplo:

Dim strNomeCliente(20) as string

Esta instrução cria um Array de 21 elementos, cada um sendo uma variável de string convencional.  Você cria 21 elementos porque o primeiro elemento de uma Array é o elemento zero (0). Iremos armazenar uma informação específica em cada um dos elementos. Exemplo:

strNomeCliente(0) = "Avelino Sampaio"
strNomeCliente(1) = "Pontocom Informática"
...
strNomeCliente(20) = "Maestro Tecnologia"

Temos aqui o nome Avelino Sampaio armazenado no elemento 0 e o nome Pontocom armazenado no elemento 1.  Se quisermos capturar o nome Avelino Sampaio da variável, basta indicarmos o seu elemento. Exemplo :

label = strNomeCliente(0)

Podemos alterar a quantidade de elementos da variável dinamicamente , através da instrução ReDim. Isto nos permitirá determinar o número exato de elementos utilizados, que será igual ao número de registros utilizados:

reDim strNomeCliente(Número de registro da tabela) as string

Preste bem atenção no código utilizado, que irá capturar os nomes dos clientes para a variável strNomeCliente

Sub fncGetItemCountCbx(control As IRibbonControl, ByRef count)
Dim rs As DAO.Recordset
Dim strSql As String
Dim j As Long
            
' Para o combobox do formulário frmClientes, faremos aqui duas tarefas:
' 1ª - Informar a quantidade de itens da lista para o Combobox.
' 2ª - Armazenar na memória do computador, os nomes dos clientes, que irão preencher 
'      a lista do controle Combobox.
'      Este conteúdo da memória será utilizado na função fncGetItemLabelCbx que será 
'      disparada logo a seguir.
            
'Monta uma consulta da tabela tblClientes para se obter os registros ordenados
'pelo nome do cliente.           
strSql = "SELECT cli_nome FROM tblClientes ORDER BY cli_nome;"
'Abre a consulta        
Set rs = CurrentDb.OpenRecordset(strSql)
rs.MoveLast: rs.MoveFirst
 
' Informa ao Combobox, através do argumento Count, a quantidade de itens que 
' serão utilizados.
 count = rs.RecordCount
 
'determina a quantidade de elementos que a variável irá armazenar
 ReDim strNomeCliente(rs.RecordCount) As String
 
'Aqui é passado para variável strNomeCliente() o nome dos clientes, registro por registro. 
 j = 0
 Do While Not rs.EOF
    strNomeCliente(j) = rs!cli_Nome
    j = j + 1
    rs.MoveNext
 Loop
 rs.Close
 Set rs = Nothing
            
End Select
End Sub

Agora o Combobox sabe quantos nomes terá que carregar na lista e passará pela função fncGetItemlabelCbx a quantidade de vezes necessárias para carregar os nomes na lista.  Veja como ficou super simples a função:

Sub fncGetItemlabelCbx(control As IRibbonControl,index As Integer, ByRef label)
'A combobox passará por esta função a quantidade de vezes igual ao número de
'registro informado na função acima.  E cada vez que passar por aqui irá 
'incrementando o argumento Index (index + 1)
 label = strNomeCliente(index)
End Sub

Observe que estamos capturando os valores armazenados na variável strNomeCliente() e o argumento Index determina qual o valor a ser capturado.  A captura está sendo realizada em seqüência.  StrNomeCliente(0), strNomeCliente(1), strNomeCliente(2), ..., strNomeCliente(n).  Os nomes se apresentarão em ordem alfabética, pois determinamos isto na ordenação da consulta.

Como usamos o valor selecionado da lista, para realizar a filtragem no formulário ?

A função fncOnChangeCbx, traz no argumento strText, o valor selecionado na lista.  Com isto podemos usar o nome do cliente para realizar a filtragem.  Acompanhe o código:

Sub fncOnChangeCbx(control As IRibbonControl, strText As String)
'Usamos o método filter para filtragem do formulário.
'strText traz o nome do cliente, selecionado pelo usuário.
Forms!frmClientes.Filter = "cli_nome='" & strText & "'"
Forms!frmClientes.FilterOn = True
'Refaz e atualiza a lista do combobox para uma nova pesquisa.
objRibbon.InvalidateControl ("cbx1")
End Sub

Veja, o controle Combobox, usado para a filtragem do formulário:

Ribbons - combobox e dropdown dinâmicas

 

Segue o exemplo para download , com os dois casos acima:

Sucesso nos seus estudos!


 

 


11 comentários

MARCIO MELO - RJ   15/11/2011 15:35:18

Melhor do que eu esperava, pois foi incrementado na própria ribbon, nos dando mais essa abrangência para enriquecer nossa tela... Tenho uns BD super simples que irei fazer utilidade desse recurso, deixando a tela mais limpa ainda... rsrs

Forte abraço! obrigado por mais essa aula

Sou mais Brasil!

Johnny-Blumenau/SC   15/11/2011 19:14:43

Beleza pura Avelino. Era o que eu precisava. Como havia lhe descrito anteriormente, implementei combo de pesquisa no form pois tive problemas para integra-la apartir da ribbon. Parabéns mais uma vez !

Johnny-Blumenau/SC   15/11/2011 19:17:03

e mais...a fartura de comentários no código só facilita o aprendizado do iniciante e a compreensão de novas rotinas para aqueles com maior conhecimento.

Lelson Barbosa   08/04/2013 10:24:07

Avelino,

em um dos meu formulários usei uma combox, por exemplo categorias de peças, mas ai quando eu peço o relatorio de uma peça ele não reconhece o campo categoria e ai eu percebi que tinha de efetuar uma consulta e deu certo, o problema é que esta consulta mostra o relatório de todas as peças quando quero apenas de uma peça específica. Espero ter sido claro, agradeço desde já.

Avelino Sampaio   14/04/2013 09:29:33

Lelson,

Veja se o exemplo abaixo atende:

Sub fncOnChangeCbx(control As IRibbonControl, strText As String)
select case strText
case "RelatórioXyz"
Docmd.OpenReport "NomeRelatório",,, "peça = '" & me!NomeDaPeça & "'"
case else
'
end select
End Sub

Sucesso!

Lelson Barbosa   17/04/2013 15:12:34

Avelino,

Muito obrigado era mesmo disso que precisava.

Ismael   03/06/2013 17:00:37

Avelino,
Como fazer para mais de um dropbox, usando o mesmo código?

Ismael   03/06/2013 22:37:29

Avelino, Usei o código conforme abaixo. O dropdown funcionou bem, mas após abrir o relatório, mesmo existindo a função invalidatecontrol, continua selecionado o item q foi aberto dentro do dropdown.


'*******************************************************************
' funções para os controles DropDown
'********************************************************************

Sub fncGetItemCountDrop(control As IRibbonControl, ByRef count)
'Informa ao dropDown, através do argumento count, a quantidade de registros da
'tabela tblListaRelatorios, que será a quantidade de linhas do dropDown.
Select Case control.Id
Case "dd_juntas"
count = DCount("*", "Tbl_DropDown")
End Select
End Sub

Sub fncGetItemlabelDrop(control As IRibbonControl, index As Integer, ByRef label)
'Informa ao dropdown, através do argumento label, o nome do relatório armazenado na tabela tblListarelatorios.
'idx é um número exclusivo para cada relatório que deverá coincidir com a posição(index) no dropdown.
Select Case control.Id
Case "dd_juntas"
label = DLookup("descricao", "Tbl_DropDown", "idx =" & index)
End Select
End Sub

Sub fncOnActionDrop(control As IRibbonControl, selectedId As String, selectedIndex As Integer)
Dim strNomeRelatorio As String
Select Case control.Id
Case "dd_juntas"
strNomeRelatorio = DLookup("relatorio", "Tbl_DropDown", "idx =" & selectedIndex)
DoCmd.OpenReport strNomeRelatorio, acViewPreview
DoCmd.Maximize
'Refaz a lista, limpando assim a caixa dropdown
objRibbon.InvalidateControl ("dd_Juntas")
End Select
End Sub

Avelino Sampaio   04/06/2013 05:24:55

Ismael,

tem um erro que cometi no projeto que está causando a falha. Como temos duas ribbons é necessário criarmos duas variáveis, para armazenamento em memória. Veja abaixo:

Option Compare Database
Public objRibbonCbx As IRibbonUI
Public objRibbonCliente As IRibbonUI
-----------------------------------------------------------------------------
Public Sub fncRibbonCbx(ribbon As IRibbonUI)
On Error Resume Next
Set objRibbonCbx = ribbon
End Sub
---------------------------------------------------------------------------
Public Sub fncRibbonCliente(ribbon As IRibbonUI)
On Error Resume Next
Set objRibbonCliente = ribbon
End Sub

Ao usar o invalidate, basta então especificar a variável correspondente:

objRibbonCbx.InvalidateControl ("dd_Juntas")

Baixe novamente o arquivo exemplo, que já está com as correções.

Sucesso!

Hephraim BF   20/01/2014 10:46:11

Muito bom!

Avelino a minha situação é a seguinte:
Quero utilizar as combos ou os dropdowns para selecionar valores que serão utilizados como critérios de filtragem dos dados dos meus forms e relatórios.

Por exemplo:
Vou utilizar 3 combos ou dropdowns.
Escola:
Tipo:
Ano

Irei preencher e depois clicar no botão visualizar ou imprimir para exibir os dados ou imprimi-los, tem como fazer isso?

madson braz   07/05/2015 16:49:07

Como ficaria duas comboboxes em cascata? onde o conteúdo da segunda é preenchido de acordo com o que for selecionado na primeira? é possível?


Envie seu comentário: