Vous êtes sur la page 1sur 9

COMBO CON OPCIÓN DE SELECCIONAR TODOS1

Una vez más, gracias a una “amable petición”, vamos a ver


este ejemplo que, por si el título no es suficientemente
explícito, nos permitirá tener un combo no sólo con los
valores cuyo origen queramos sino que tendrá una primera
opción para seleccionar “Todos”.

El ejemplo lo dividiremos en dos partes: la primera, la fácil, donde


tendremos únicamente una sola columna con valores. La segunda,
un poco más compleja, donde tendremos dos columnas: una con
un identificador y otra con el texto correspondiente. Esta segunda
opción nos servirá para poder seguir operando “normalmente” si
trabajamos con relaciones a través de identificadores.

Ya sabemos que un combo puede tener múltiples utilidades una vez seleccionado el valor que
queremos. Para este ejemplo, y por hacerlo lo más gráfico y simple posible, lo que haremos
será utilizarlo para filtrar los datos de un formulario continuo.

Dicho lo cual, pues al ataque.

PRIMERA PARTE
NUESTRAS TABLAS
Imaginemos que tenemos una lista de libros, y queremos poder filtrar, en un formulario, según
su género.

Eso nos delimita la necesidad de tener dos tablas, una para los datos de los libros y otra,
auxiliar, para los géneros.

Empezaremos por la simple, la de un solo campo, que llamaremos TGeneros y que tendrá la
siguiente estructura:

Por si alguien no tiene claro a qué llamo género ahí van algunos datos:

Nos creamos otra tabla (muy simplificada), que llamaremos TLibros, con la siguiente
estructura:

1 La BD de ejemplo os la podéis bajar aquí

1
Visítame en http://neckkito.siliconproject.com.ar
Lógicamente faltan bastantes campos (autor, editorial,
Isbn…). Pero ahora eso no es lo importante.

Para definir el tipo de datos del campo [GeneroLibro] he


seleccionado, como tipo, el asistente para búsquedas,
diciéndole que me coja, de la tabla TGeneros, el valor del
campo [Genero].

NUESTRO FORMULARIO
Vamos a crearnos un formulario sobre TLibros, que llamaremos FLibros. Sin embargo, lo
crearemos de manera que sea un formulario continuo (varios elementos).

En la sección <Encabezado de formulario> vamos a añadir un cuadro combinado. A ese combo


le pondremos de nombre cboFiltro2. En principio lo crearemos independiente (es decir, que si
nos sale el asistente lo cancelaremos y tan contentos).

Vamos a sacar las propiedades de ese combo y nos vamos a la pestaña...

 Formato → Ancho de columnas, y ahí le escribimos un valor para poder ver nuestros
“futuros” datos. Por ejemplo, le escribimos “2cm” (sin las comillas)

 Datos → Tipo de origen de la fila, y ahí seleccionamos “Lista de valores”


→ Limitar a la lista: Sí
→ Permitir ediciones de lista: No

Ya tenemos nuestro combo casi cocido; nos falta la “pizca de sal”. Para ello, en su evento “Al
recibir el enfoque” vamos a generar el siguiente código3:


Private Sub cboFiltro_GotFocus()

'*---Neckkito---------------------------.-
'*---19/06/16---------------------------.-
'*--------------------------------------.-

Dim listaValores As String


Dim miSql As String
Dim rst As DAO.Recordset

'Nos creamos una simple SQL que nos seleccione todos los registros de TGeneros
miSql = "SELECT Genero FROM TGeneros ORDER BY Genero"

'Nos creamos un recordset sobre la Sql


Set rst = CurrentDb.OpenRecordset(miSql)
If rst.RecordCount = 0 Then Exit Sub 'Si no hay registros en la tabla salimos

'Inicializamos la lista de valores con unas comillas dobles

2 Para asignar un nombre a un control lo que debemos hacer es sacar las propiedades de ese control e irnos a la Pestaña Otras →
Nombre. Ahí escribimos el nombre que queramos.
3 Para generar código debemos sacar las propiedades del control → Pestaña Eventos, y nos situamos en la parte “blanca” a la
derecha del evento que queremos programar. Veremos un pequeño botón de puntos suspensivos. Si hacemos clic sobre él nos
aparecerá una ventana que nos pedirá qué operación deseamos realizar. Le indicamos que queremos “generar código”.

2
Visítame en http://neckkito.siliconproject.com.ar
listaValores = Chr(34) & listaValores

'Recorremos uno a uno los registros del recordset


With rst
.MoveFirst
Do Until .EOF
'Empezamos a crear la lista con los valores de [Genero], que se corresponde con el campo cero.
'Le añadimos comillas dobles tras el valor, añadimos punto y coma (;) al final como separador de listas
'y de nuevo unas comillas dobles
listaValores = listaValores & .Fields(0).Value & Chr(34) & ";" & Chr(34)
.MoveNext
Loop
End With

'Ahora tenemos una lista de valores con un punto y coma (;) y comillas dobles finales, que nos sobran. Los
quitamos
listaValores = Left(listaValores, Len(listaValores) - 2)

'Sólo nos falta anteponer la opción "Todos" (con comillas incluidas) a nuestra lista. Así que...
listaValores = Chr(34) & "Todos" & Chr(34) & ";" & listaValores

'Asignamos esa lista como origen de la fila del combo


Me.cboFiltro.RowSource = listaValores

'Refrescamos la información en el combo


Me.cboFiltro.Requery

'Cerramos conexiones y liberamos memoria


rst.Close
Set rst = Nothing

End Sub

El código está comentado. Lo interesante es que intentéis entender cómo se va construyendo


la lista de valores teniendo en cuenta la “relativa complejidad” del formato que debe resultar,
es decir:

comillasDobles-Valor-comillasDobles-PuntoYComa-comillasDobles-Valor-…

Y sabiendo que el último elemento no debe llevar tras él más que unas comillas dobles.

Ahora sólo nos falta saber qué pasa tras seleccionar un valor. Para ello, en el evento “Después
de actualizar del combo”, generamos el siguiente código:


Private Sub cboFiltro_AfterUpdate()
Dim elValor As String
Dim miFiltro As String

'Cogemos el valor del combo. Si no hay valor salimos


elValor = Nz(Me.cboFiltro.Value, "")
If elValor = "" Then Exit Sub

3
Visítame en http://neckkito.siliconproject.com.ar
'Analizamos si el valor es "Todos" o es otro
If elValor = "Todos" Then
Me.FilterOn = False 'Quitamos el filtro
Else
miFiltro = "[GeneroLibro]='" & elValor & "'"
Me.Filter = miFiltro
Me.FilterOn = True 'Filtramos
End If
End Sub

Y con esto tenemos ya esta primera parte finiquitada.

SEGUNDA PARTE
Llegados a este punto quizá alguien pueda decirme: pues con un combo con dos columnas el
proceso será el mismo. ¿Para qué te enrollas con esta segunda parte?

Mi respuesta en ese caso sería sí y no. Sí, porque la base del sistema es, básicamente (valga la
“rebuznancia”), la misma; no, porque hay pequeños detalles que difieren del proceso anterior,
pequeños pero que pueden hacer que no nos salga nada en absoluto.

Por otra parte, mi idea no es repetir lo mismo que en la primera parte, sino que lo que os voy
a explicar es una manera de automatizar el sistema y que podamos aplicarlo rápidamente a
cualquier combo en nuestra aplicación que requiera de ese añadido para “todos”.

Veamos...

NUESTRAS TABLAS
A nuestro control de libros vamos a añadir los autores. Pero queremos manejar los autores a
través de identificadores.

Para ello crearemos una nueva tabla, que llamaremos TAutores, con la siguiente estructura
simple.

Ojo: el tipo “Texto corto” es Access 2013; en versiones anteriores es “Texto”.

Vamos a reciclar nuestra tabla de libros. La copiaremos y la pegaremos como TLibros2. A


continuación añadiremos un campo que será [AutorLibro]. Para definir su tipo nos iremos al
tipo “Asistente para búsquedas” y le diremos que queremos, de TAutores, sus dos campos. Es
indiferente si queréis mostrar o no la clave principal.

Es decir, que TLibros2 tiene unas pintas como estas:

4
Visítame en http://neckkito.siliconproject.com.ar
NUESTRO FORMULARIO
Nos creamos un formulario sobre TLibros2, que llamaremos FLibros2. Como vamos a utilizar
para filtrar información lo crearemos como un formulario continuo (varios elementos). Sin más
secretos.

A continuación, en la sección encabezado, vamos a insertar un cuadro combinado


independiente; es decir, insertamos un combo y, cuando nos salga el asistente, cancelamos. A
ese cuadro combinado lo llamaremos cboFiltro2.

Vamos a manipular las propiedades del combo. Así:

 Formato → Número de columnas: le indicamos que queremos 2


→ Ancho de columnas, y ahí le escribimos unos valores para poder ver nuestros
“futuros” datos. Por ejemplo, le escribimos “0cm;2cm” (sin las comillas).

Al escribir un primer ancho de 0cm lo que estamos haciendo es ocultar la primera columna,
que usualmente es la clave principal. Si nos interesara verla pues le damos un ancho, por
poner un ejemplo, de “0,5cm”.

También, dependiendo de los caracteres, tendremos que jugar con las medidas para encontrar
la que se adapte mejor a nuestros contenidos de información.

 Datos → Tipo de origen de la fila, y ahí seleccionamos “Lista de valores”


→ Limitar a la lista: Sí
→ Permitir ediciones de lista: No
→ Columna dependiente: nos aseguramos que sea la 1, dado que es la que
contendrá el identificador del autor.

El código para el evento “Después de actualizar” de ese combo será prácticamente igual al
explicado en la primera parte, sólo que adaptado para que filtre por un valor numérico. Es
decir, que será el siguiente:


Private Sub cboFiltro2_AfterUpdate()
Dim elValor As Long
Dim miFiltro As String

'Cogemos el valor del combo. Si no hay valor salimos


elValor = Nz(Me.cboFiltro2.Value, -1)
If elValor = -1 Then Exit Sub

'Analizamos si el valor es "Todos", es decir, clave=0, o es otro


If elValor = 0 Then
Me.FilterOn = False 'Quitamos el filtro
Else

5
Visítame en http://neckkito.siliconproject.com.ar
miFiltro = "[AutorLibro]=" & elValor
Me.Filter = miFiltro
Me.FilterOn = True 'Filtramos
End If

End Sub

Fijados que vamos a reservar el valor cero para “Todos”, por


lo que para controlar valores vacíos (nulos) hacemos que la
función Nz() devuelva -1.

Y, por ahora, dejamos a nuestro combo descansar de la operación


quirúrgica. Volveremos a él un poco más tarde. Tras el siguiente
epígrafe le asignaremos un código que entenderéis mejor que si lo
hiciéramos ahora.

NUESTRO MÓDULO
Para poder convertir nuestra operativa en algo aplicable a cualquier combo que queramos
debemos inventarnos algún procedimiento que nos rellene los datos de cualquier combo. Y eso
lo vamos a conseguir a través de un módulo estándar.

Así pues insertamos un módulo estándar que llamaremos mdlRellenoCombo4.

En ese módulo insertaremos un procedimiento público. Pero antes de daros el código vamos a
reflexionar un momento:

 ¿Qué necesito que me muestre el combo? Pues en nuestro ejemplo, necesitamos el


identificador del autor y su nombre. Hasta aquí fácil, ¿verdad?

 ¿Dónde puedo encontrar esos valores? Pues esos valores están en la tabla TAutores, en
los campos [IdAutor] y [NomAutor].

De lo anterior podemos deducir que vamos a necesitar el nombre de la tabla y el nombre del
campo que será nuestra columna 1 y el nombre del campo que será nuestra columna 2 del
combo.

¿Vamos bien?

Podríamos pensar que ya tenemos la reflexión hecha, pero… ¡un momento! El código está en
un módulo estándar, no en un formulario. Entonces,

 ¿Qué combo debemos rellenar? Pues en nuestro caso el cboFiltro2.


De lo anterior podemos deducir que vamos a necesitar el nombre del combo que queremos
rellenar.

¿Seguimos?

 ¿Qué pasaría si tenemos varios formularios con combos, y a todos les hemos
llamado cboFiltro2? Pues que necesitamos decirle que lo que queremos rellenar es el
cboFiltro2 del formulario FLibros2.

4 Para insertar un módulo estándar podemos abrir el editor de VB (ALT+F11) y nos vamos a Menú → Insertar → Módulo

6
Visítame en http://neckkito.siliconproject.com.ar
En consecuencia, necesitaremos también el nombre del formulario en el que se encuentra el
combo a rellenar.

¿Necesitamos algo más? Pues yo creo que no, pues


tenemos los elementos necesario para decirle a Access:
relléname en el formulario X el combo Y con los campos A y
B que están en la tabla Z.

Hablando en términos de programación, acabamos de


definir los parámetros que requiere nuestro procedimiento.

Así pues, en nuestro módulo, bajo la/s línea/s “Option”,


escribimos el siguiente código:


'-----------------------------------------------------------------------------------------------------------------------
'-------Código programado por Neckkito @ http://neckkito.siliconproject.com.ar
'-------Fecha creación: 20/06/15
'-------Fecha última modificación: 20/06/15
'-----------------------------------------------------------------------------------------------------------------------
'-------La llamada se realiza desde el evento "Al recibir el enfoque" del combo, y se le deben pasar los siguientes
'-------parámetros, por este orden: nombre del campo 1, nombre del campo 2, nombre de la tabla, nombre del combo
'-------y el objeto formulario en el que está el combo. Ejemplo:
'-------Call subRellenoCbo("NombreCampo1", "NombreCampo2", "NombreTabla", Me.NombreCbo.Name, Me)
'-----------------------------------------------------------------------------------------------------------------------

Public Sub subRellenoCbo( _


campo1 As String, _
campo2 As String, _
laTabla As String, _
elCbo As String, _
elForm As Form)

On Error GoTo sol_err

Dim listaValores As String


Dim miSql As String
Dim rst As DAO.Recordset

Dim vCampo1 As Long 'Porque cogemos un identificador autonumérico


Dim vCampo2 As String 'Porque cogemos un campo de tipo texto

'Nos creamos una simple SQL que nos seleccione todos los registros de los campos indicados, y de la tabla
especificada
miSql = "SELECT [" & campo1 & "], [" & campo2 & "]" _
& " FROM " & laTabla & " ORDER BY [" & campo2 & "]"

'Nos creamos un recordset sobre la Sql


Set rst = CurrentDb.OpenRecordset(miSql)
If rst.RecordCount = 0 Then Exit Sub 'Si no hay registros en la tabla salimos

'Inicializamos la lista de valores con unas comillas dobles


listaValores = Chr(34) & listaValores

'Recorremos uno a uno los registros del recordset


With rst
.MoveFirst
Do Until .EOF
'Asignamos valores a vCampo1 y vCampo2. Aprovechamos para controlar que efectivamente haya valor
vCampo1 = Nz(.Fields(0).Value, -1)
vCampo2 = Nz(.Fields(1).Value, "")

'Realizamos la comprobación
If vCampo1 = -1 Or vCampo2 = "" Then 'Si no hay valores los saltamos
'No hago nada y dejo que se llegue al End If
Else
'Empezamos a crear la lista con los valores.

7
Visítame en http://neckkito.siliconproject.com.ar
'Le añadimos comillas dobles tras el valor, añadimos punto y coma (;) al final como separador de listas
'y de nuevo unas comillas dobles
listaValores = listaValores & vCampo1 & Chr(34) & ";" & Chr(34)
listaValores = listaValores & vCampo2 & Chr(34) & ";" & Chr(34)
End If
.MoveNext
Loop
End With

'Ahora tenemos una lista de valores con un punto y coma (;) y comillas dobles finales, que nos sobran. Los
quitamos
listaValores = Left(listaValores, Len(listaValores) - 2)

'Sólo nos falta anteponer la opción "0-Todos" (con comillas incluidas) a nuestra lista. Así que...
listaValores = Chr(34) & "0" & Chr(34) & ";" & Chr(34) & "Todos" & Chr(34) & ";" & listaValores

With elForm.Controls(elCbo)
'Asignamos esa lista como origen de la fila del combo
.RowSource = listaValores
'Refrescamos la información en el combo
.Requery
End With

'Cerramos conexiones y liberamos memoria


rst.Close
Set rst = Nothing

Salida:

Exit Sub

sol_err:

Select Case Err.Number


Case 3061
MsgBox "Alguno o ambos nombres de los campos no son correctos", vbCritical, "ERROR"
Case 3078
MsgBox "El nombre de la tabla es incorrecto", vbCritical, "ERROR"
Case 438
MsgBox "La expresión que devuelve el nombre del combo no es correcta", vbCritical, "ERROR"
Case Else
MsgBox "Se ha producido el error " & Err.Number & " - " & Err.Description, _
vbCritical, "ERROR"
End Select

Resume Salida

End Sub

Fijaos que todo el tiempo estoy manejando, llamémosle, “pares de datos”. Eso es porque el
combo entiende que, en nuestro ejemplo, el primer miembro del par es un elemento de la
columna 1 del combo y el segundo miembro del par es un elemento de la segunda columna.
De ahí que haga la comprobación de si existe valor antes de añadir los elementos a la lista. Si

8
Visítame en http://neckkito.siliconproject.com.ar
no lo hiciera así, a partir del primer elemento vacío, me saldrían los datos desapareados en el
combo.

Lógicamente, si necesitamos más columnas en el combo


debería manejar tuplas de 3 elementos cada vez,
correspondientes a las columnas 1, 2 y 3.

Fijaos también que utilizo y declaro las siguientes variables:


Dim vCampo1 As Long 'Porque cogemos un identificador autonumérico
Dim vCampo2 As String 'Porque cogemos un campo de tipo texto

Si nuestro campo 2 contuviera un valor de tipo numérico deberíamos adaptar la declaración de


la segunda variable al tipo definido en ese campo. Si, por ejemplo, en la tabla lo tuviéramos
como numérico-entero largo, la declaración sería:


Dim vCampo2 As Long

En consecuencia, cuando controláramos si hay valor, deberíamos adaptar también el control al


tipo de campo, así:


vCampo2 = Nz(.Fields(1).Value, -1)

If vCampo1 = -1 Or vCampo2 = -1 Then 'Si no hay valores los saltamos

En la BD que acompaña a este ejemplo hay un combo en el formulario FMenu que, además de
servir para hacer testeos, permite ver que una vez tenemos el módulo en nuestra aplicación es
muy sencillo realizar una llamada a nuestro procedimiento.

PARA FINALIZAR EL EJEMPLO


Bueno… Pues espero que os haya quedada clara la mecánica de cómo construirnos un combo
“personalizado” que nos permita incluir la opción “Todos” en el mismo.

Un saludo, y…

¡suerte!

9
Visítame en http://neckkito.siliconproject.com.ar

Vous aimerez peut-être aussi