INTRODUCIR MÚLTIPLES VALORES EN UN INPUTBOX

Hola a todos!.

Qué tal estáis? espero que bien! y supongo que muchos de vosotros ya estáis disfrutando de las vacaciones o esperando a que lleguen.

Hoy voy a comentar una solución que le ofrecí a un lector que me consultaba cómo podría introducir en un inputbox dos o más datos. Normalmente esta tarea se realiza con un formulario o userform, habilitando tantos cuadros de texto como sean necesarios.

Pero en el caso del inputbox solo tenemos un cuadro de texto, sin posibilidad de poder crear más cuadros de texto. Lo que nos obligaría a crear tantos inputbox como datos necesitemos introducir.

Pero existe una solución para poder introducir valores múltiples en un inputbox. Veamos un ejemplo, imaginad que queréis pasar dos fechas (Inicio y Fin) a través del mismo inputbox y mostrar los datos en las siguientes celdas:

INTRODUCIR MÚLTIPLES VALORES EN UN INPUTBOX

Para poder hacerlo, vamos a utilizar el siguiente código que he programado:

Sub INPUT_VARIOS()
'Declaramos las variables
Dim formulario, miarray
'Invocamos inputbox e indicamos las fechas separadas por una coma
formulario = InputBox("INDICA FECHA INICIO Y FECHA FIN SEPARADO POR UNA COMA:" & Chr(13) & Chr(13) & "EJEM: 01/01/2018,01/03/2018", "FECHAS")
'Si no ponemos nada, salimos del proceso
If formulario = Empty Then Exit Sub
'verificamos que los datos introducidos son correctos, si hay errores, los detectamos al final
On Error GoTo etiqueta
'Pasamos las dos fechas a una matriz utilizando la función split
miarray = Split(formulario, ",")
'Pasamos los datos a cada celda igualando los array
With Sheets("Hoja1")
.Cells(2, 1) = CDate(miarray(0))
.Cells(2, 2) = CDate(miarray(1))
End With
Exit Sub
etiqueta:
MsgBox ("Verifica los datos que has introducido e inténtalo de nuevo"), vbExclamation
End Sub

Al ejecutarlo veremos el siguiente inputbox en nuestra hoja:

INTRODUCIR MÚLTIPLES VALORES EN UN INPUTBOX_1

Como podéis observar en la macro, estamos utilizando la función split para pasar la información que hemos indicado en cuadro de texto del inputbox a una matriz. Como necesitamos indicar un elemento o carácter que separe las dos fechas (o cualquier otro dato), he decido utilizar la coma “,”aunque podríamos usar el punto y coma, “;” una arroba “@” etc, sustituyéndolo en la macro:

miarray = Split(formulario, ",")

Una vez que tenemos ambos datos, tan solo tendremos que pasar la información a las celdas de la hoja que necesitamos rellenar y lo hacemos pulsando en el botón aceptar de nuestro inputbox. Como cortesía hacia el lector, he programados varias líneas de código para controlar los datos erróneos o que surjan errores a la hora de ejecutar la macro.

El resultado es que tenemos en las celdas la información indicada en el cuadro de texto:

INTRODUCIR MÚLTIPLES VALORES EN UN INPUTBOX_2

Y eso es todo, como podéis observar sí es posible introducir valores múltiples en un inputbox.

Descarga el archivo de ejemplo pulsando en: INTRODUCIR MÚLTIPLES VALORES EN UN INPUTBOX

¿Te ha resultado de interés?, puedes apoyar a Excel Signum con una pequeña donación.

Donate Button with Credit Cards

¡¡Muchas gracias!!

Mediante la suscripción al blog, la realización comentarios o el uso del formulario de contacto estás dando tu consentimiento expreso al tratamiento de los datos personales proporcionados según lo dispuesto en la ley vigente (LOPD). Tienes más información al respecto en esta página del blog: Política de Privacidad y Cookies

Anuncios

ELIMINAR DUPLICADOS DIRECTAMENTE SOBRE EL CONTENIDO DE UN LISTBOX

Hola a todos:

Ya sabéis que en esta web hay varias entradas que tratan el tema de los duplicados o cómo obtener registros únicos en nuestras informaciones, tanto en formularios como en bases de datos y usando métodos diferentes.

Sin embargo, esta semana un lector me solicitaba lo siguiente:

¿Es posible quitar los duplicados de un listbox mediante un boton
tomando los datos directamente del listbox sin tener que guardar la informacion a una hoja o tabla de calculo y que mantengan el mismo orden en el que fueron encontrados los registros por primera vez?

Es decir, interactuar directamente con el contenido del listbox sin posibilidad de acudir a la fuente de los datos y eliminar los duplicados antes de cargar la información en el listbox.

Aunque soy partidario de tratar la información antes de enviarla a un listbox (o combobox, etc…), lo cierto es que sí es posible hacer lo que el lector solicita. Y ese es el objetivo de este post.

Vamos a tomar un ejemplo en el que tenemos una base de datos con duplicados:

ELIMINAR DUPLICADOS DIRECTAMENTE SOBRE EL CONTENIDO DE UN LISTBOX

Estos datos los pasamos a un listbox en nuestro formulario y el código que utilizaremos para cargar el listbox es el siguiente:

Private Sub UserForm_Initialize()
Dim fin As Long
'Indicamos el número de columnas que tendrá el listbox
Me.ListBox1.ColumnCount = 7
'Definimos tamaño de los espacios
Me.ListBox1.ColumnWidths = "30pt;150pt;150pt;50pt;50pt;60pt"
'Cargamos listbox
With Sheets("BBDD")
fin = Application.CountA(.Range("A:A"))
Me.ListBox1.List = .Range("A2:G" & fin).Value
End With
End Sub

Es importante usar la propiedad listbox.list para cargar la información, dado que nos posibilitará el poder eliminar duplicados directamente en el listbox con el método RemoveItem.

ELIMINAR DUPLICADOS DIRECTAMENTE SOBRE EL CONTENIDO DE UN LISTBOX1

Podéis ver que nuestro listbox muestra todos los duplicados, pues bien, para eliminar los duplicados usaremos esta otra macro, vinculada al botón de comando “ELIMINAR DUPLICADOS”:

Private Sub CommandButton1_Click()
'Declaramos variables
Dim i As Long, j As Long
With ListBox1
'Eliminamos duplicados
For i = 0 To .ListCount - 1
For j = .ListCount - 1 To (i + 1) Step -1
If .List(j) = .List(i) Then .RemoveItem j
Next j
Next i
End With
End Sub

Una vez que hemos pulsado el botón, automáticamente se eliminan los duplicados en nuestro listbox, así:

ELIMINAR DUPLICADOS DIRECTAMENTE SOBRE EL CONTENIDO DE UN LISTBOX2

Pues bien, el utilizar la propiedad .list nos ha permitido solucionar este problema. Ahora ya tenemos nuestro listbox sin duplicados y listo para ser usado en otras tareas.

Espero que os haya resultado interesante y que os pueda ayudar en vuestros trabajos y proyectos.

Como siempre, os dejo el archivo de ejemplo : )

Descarga el archivo de ejemplo pulsando en: ELIMINAR DUPLICADOS DIRECTAMENTE SOBRE EL CONTENIDO DE UN LISTBOX

¿Te ha resultado de interés?, puedes apoyar a Excel Signum con una pequeña donación.

Donate Button with Credit Cards

¡¡Muchas gracias!!

REALIZAR BÚSQUEDAS DEPENDIENTES EN UN LISTBOX

Hola a todos : )

Hace unos días me enviaron una consulta en la que me solicitaban la necesidad de poder realizar consultas dependientes en un listbox.

Sobre el tema de las consultas dependientes, ya había tratado algo en esta entrada: COMBOBOX DEPENDIENTES EN USERFORM CON SQL , solo que esa ocasión estaba utilizando combobox.

En concreto, en esa consulta el filtro debería hacerse sobre un único listbox y utilizando varios textbox para indicar los items por los que realizar el filtrado.

Utilizará la base de datos de empleados de unos grandes almacenes (ya es un clásico en esta web) y pasaré los datos a un listbox:

Esta es la base de datos:

REALIZAR BUSQUEDAS DEPENDIENTES EN UN LISTBOX

Y mediante este código pasamos la información al listbox:

Private Sub UserForm_Initialize()
'Indicamos el número de columnas que tendrá el listbox
Me.ListBox1.ColumnCount = 7
'Definimos tamaño de los espacios
Me.ListBox1.ColumnWidths = "30pt;150pt;150pt;50pt;50pt;60pt"
'Cargamos listbox
Me.ListBox1.RowSource = ("A2:G") & Worksheets("BBDD").Range("A" & Rows.Count).End(xlUp).Row
End Sub

Aquí ya tenemos la información cargada:

REALIZAR BUSQUEDAS DEPENDIENTES EN UN LISTBOX2

Pero ahora debemos filtrar según nuestras necesidades. Para este ejemplo realizaré un secuencia de tres consultas dependientes: Primero filtramos por Sección, una vez tengamos esos datos, filtramos por Estudios y finalmente, filtraremos por Idioma.

Para ello es necesario crear tres textbox, y en cada uno de ellos realizar la programación correspondiente. Os dejo el código de cada textbox:

TextBox1 – Filtrar por Sección:

Private Sub TextBox1_Change()
'Declaramos variables
Dim fin As Long, i As Long, n As Long
Dim sCadena_seccion As String
'Filtramos por sección
With Sheets("BBDD")
fin = Application.CountA(.Range("A:A"))
If TextBox1 = "" Then
Me.ListBox1.RowSource = ("A2:G") & Worksheets("BBDD").Range("A" & Rows.Count).End(xlUp).Row
Exit Sub
End If
Me.TextBox2 = Clear
Me.TextBox3 = Clear
Me.ListBox1.RowSource = Clear
For i = 2 To fin
sCadena_seccion = .Cells(i, 3).Value
If UCase(sCadena_seccion) Like "*" & UCase(TextBox1.Value) & "*" Then
Me.ListBox1.AddItem
Me.ListBox1.List(n, 0) = .Cells(i, 1).Value
Me.ListBox1.List(n, 1) = .Cells(i, 2).Value
Me.ListBox1.List(n, 2) = .Cells(i, 3).Value
Me.ListBox1.List(n, 3) = .Cells(i, 4).Value
Me.ListBox1.List(n, 4) = .Cells(i, 5).Value
Me.ListBox1.List(n, 5) = .Cells(i, 6).Value
Me.ListBox1.List(n, 6) = .Cells(i, 7).Value
n = n + 1
End If
Next
Me.ListBox1.ColumnWidths = "30pt;150pt;150pt;50pt;50pt;60pt"
End With
End Sub

TextBox2 – Filtrar por Estudios:

Private Sub TextBox2_Change()
Dim fin As Long, i As Long, n As Long
Dim sCadena_seccion As String, sCadena_estudios As String
'Una vez filtrados los datos por sección, filtramos por estudios
With Sheets("BBDD")
fin = Application.CountA(.Range("A:A"))
If TextBox2 = "" Then
Me.ListBox1.RowSource = ("A2:G") & Worksheets("BBDD").Range("A" & Rows.Count).End(xlUp).Row
Exit Sub
End If
Me.ListBox1 = Clear
Me.ListBox1.RowSource = Clear
For i = 2 To fin
sCadena_seccion = .Cells(i, 3).Value
sCadena_estudios = .Cells(i, 7).Value
If UCase(sCadena_seccion) Like "*" & UCase(TextBox1.Value) & "*" And _
UCase(sCadena_estudios) Like "*" & UCase(TextBox2.Value) & "*" Then
Me.ListBox1.AddItem
Me.ListBox1.List(n, 0) = .Cells(i, 1).Value
Me.ListBox1.List(n, 1) = .Cells(i, 2).Value
Me.ListBox1.List(n, 2) = .Cells(i, 3).Value
Me.ListBox1.List(n, 3) = .Cells(i, 4).Value
Me.ListBox1.List(n, 4) = .Cells(i, 5).Value
Me.ListBox1.List(n, 5) = .Cells(i, 6).Value
Me.ListBox1.List(n, 6) = .Cells(i, 7).Value
n = n + 1
End If
Next
Me.ListBox1.ColumnWidths = "30pt;150pt;150pt;50pt;50pt;60pt"
End With
End Sub

TextBox3 – Filtrar por Idiomas:

Private Sub TextBox3_Change()
Dim fin As Long, i As Long, n As Long
Dim sCadena_seccion As String, sCadena_estudios As String, sCadena_idioma As String
'una vez filtrada la información por sección y estudios, filtramos por idioma

With Sheets("BBDD")

fin = Application.CountA(.Range("A:A"))
If TextBox2 = "" Then
Me.ListBox1.RowSource = ("A2:G") & Worksheets("BBDD").Range("A" & Rows.Count).End(xlUp).Row
Exit Sub
End If
Me.ListBox1 = Clear
Me.ListBox1.RowSource = Clear
For i = 2 To fin
sCadena_seccion = .Cells(i, 3).Value
sCadena_estudios = .Cells(i, 7).Value
sCadena_idioma = .Cells(i, 6).Value
If UCase(sCadena_seccion) Like "*" & UCase(TextBox1.Value) & "*" And _
UCase(sCadena_estudios) Like "*" & UCase(TextBox2.Value) & "*" And _
UCase(sCadena_idioma) Like "*" & UCase(TextBox3.Value) & "*" Then
Me.ListBox1.AddItem
Me.ListBox1.List(n, 0) = .Cells(i, 1).Value
Me.ListBox1.List(n, 1) = .Cells(i, 2).Value
Me.ListBox1.List(n, 2) = .Cells(i, 3).Value
Me.ListBox1.List(n, 3) = .Cells(i, 4).Value
Me.ListBox1.List(n, 4) = .Cells(i, 5).Value
Me.ListBox1.List(n, 5) = .Cells(i, 6).Value
Me.ListBox1.List(n, 6) = .Cells(i, 7).Value
n = n + 1
End If
Next
Me.ListBox1.ColumnWidths = "30pt;150pt;150pt;50pt;50pt;60pt"
End With
End Sub

Una vez te tenemos el código incluido en todos los controles, ya podemos proceder a probar la herramienta. Probaremos con la siguiente consulta: todos los empleados que pertenezcan a la sección de “Bricolaje“, que en sus estudios sean “Diplomados” y que sepan “Chino“.

El resultado es el siguiente:

REALIZAR BUSQUEDAS DEPENDIENTES EN UN LISTBOX3

Como podéis observar, el filtro funciona perfectamente y no es necesario escribir la palabra completa en los textbox, basta con ir escribiendo y la información se irá mostrando. En este caso tenemos a dos personas, perfecto!.

Y eso es todo, creo que es un método muy sencillo, donde trabajamos con un loop, un buscador y cargamos información si los parámetros de la consulta coinciden.

Espero que os resulte de interés : )

Descarga el archivo de ejemplo pulsando en: REALIZAR BÚSQUEDAS DEPENDIENTES EN UN LISTBOX

¿Te ha resultado de interés?, puedes apoyar a Excel Signum con una pequeña donación.

Donate Button with Credit Cards

¡¡Muchas gracias!!

ELIMINAR REGISTROS DUPLICADOS Y ORDENAR ALFABÉTICAMENTE LA INFORMACIÓN

Hola a todos:

En el post anterior hemos visto una nueva técnica para obtener registros únicos usando el objeto “Diccionario”: ELIMINAR REGISTROS DUPLICADOS Y CARGAR DATOS ÚNICOS EN COMBOBOX Y LISTBOX

Entre las consultas que me enviaron los lectores, una de ellas era sobre si se podían ordenar esos datos una vez eliminados los duplicados y pasar esa información al combobox y al listbox. Como me pareció útil e interesante, he decidido crear un nuevo post como continuación al anterior (de esta forma se verá más claro).

Partiendo de una información diferente, no meses, sino por nombre de personas:

ELIMINAR REGISTROS DUPLICADOS Y ORDENAR ALFABETICAMENTE LA INFORMACION

Vamos a hacer el mismo ejercicio que en post anterior, es decir, eliminar duplicados, ordenar la información y pasar los datos a un combobox y a un listbox:

Sub CARGAR_UNICOS_ORDENADOS()
'Declaramos las variables
Dim rango As Range, celda As Object, oDic As Object, npalabra As String
Dim sCadena As String, sCadena1 As String, ipalabra As String, OrdenarAlfa As Variant
Dim matriz As Variant, matriz1 As Variant, palabra As Variant, alfadato As Variant
Dim i As Long, j As Long, fin As Integer
'Trabajamos con la hoja
With Sheets("UNICOS")
'Limpiamos combo y listbox
.ComboBox1.Clear
.ListBox1.Clear
'Definimos el rango de los datos
fin = .Range("A" & Rows.Count).End(xlUp).Row
'Trabajamos con rango establecido
Set rango = .Range("A2:A" & fin)
'Por cada celda del rango componemos un string
For Each celda In rango
If celda <> vbNullString Then
ipalabra = ipalabra & "," & celda
End If
Next celda
'Eliminamos posibles espacios en blanco
sCadena = Trim(Mid(ipalabra, 2, Len(ipalabra)))
'Comprobamos que cada palabra que incluimos en la matriz no existe en cadena
matriz = Split(sCadena, ",")
Set oDic = CreateObject("scripting.dictionary")
For i = 0 To UBound(matriz)
If Not oDic.Exists(matriz(i)) Then oDic.Add matriz(i), matriz(i)
Next i
'Creamos una nueva cadena ya sin duplicados
sCadena1 = Join(oDic.Keys, ",")
'Pasamos los datos a una matriz
Set matriz1 = CreateObject("System.Collections.ArrayList")
'Y ordenamos las palabras
For Each palabra In Split(sCadena1, ",")
matriz1.Add palabra
Next palabra
matriz1.Sort
'Pasamos de nuevo las palabras ordenadas a un string
For Each alfadato In matriz1
npalabra = npalabra & "," & alfadato
Next alfadato
OrdenarAlfa = Split(Trim(Mid(npalabra, 2, Len(npalabra))), ",")
'Pasamos los datos al Combo y al listbox
For j = 0 To UBound(OrdenarAlfa)
.ComboBox1.AddItem (OrdenarAlfa(j))
.ListBox1.AddItem (OrdenarAlfa(j))
Next
'Limpiamos variable de objeto
Set rango = Nothing
Set oDic = Nothing
End With
End Sub

Si vais observando la construcción de la macro, podéis ver que hemos incluido un pequeño subproceso en el código a través del cual volvemos a pasar los datos del rango a una matriz y los ordenamos con la propiedad “.sort”.

El resto del código es igual que el ejemplo anterior, y para que veáis cómo funciona, os dejo el resultado:

ELIMINAR REGISTROS DUPLICADOS Y ORDENAR ALFABETICAMENTE LA INFORMACION1

Como podéis observar, hemos conseguir el objetivo propuesto, los datos se han cargado sin duplicados y se han ordenado alfabéticamente.

Descarga el archivo de ejemplo pulsando en: ELIMINAR REGISTROS DUPLICADOS Y ORDENAR ALFABÉTICAMENTE LA INFORMACIÓN

¿Te ha resultado de interés?, puedes apoyar a Excel Signum con una pequeña donación.

Donate Button with Credit Cards

¡¡Muchas gracias!!

CALCULAR LA EDAD CON DATEDIF EN UN FORMULARIO DE EXCEL

Hola a todos, espero que estéis bien y supongo que ya disfrutando de vacaciones (a mí aún me quedan unas semanas para comenzarlas).

En el post de hoy vamos a tratar de resolver una consulta que me enviaron la semana pasada sobre un tema que ya hace tiempo que tenía ganas de abordar. La pregunta era cómo se podía calcular la edad en un formulario de Excel.

Bien, existen varios post sobre el cálculo de la edad en esta web, y en todas ellas usamos la función SIFECHA() de excel, que normalmente la usamos en la hoja y en menor medida en VBA. En VBA esta función se denomina DATEDIF (y NO es lo mismo que otra función denominada DATEDIFF, que trabaja con valores absolutos).

Esta función, si utilizamos la grabadora de datos para obtener su traducción en VBA sería algo así:

AÑO = "=DATEDIF(RC[-12],TODAY(),""Y"")"

Es decir, nos ofrece la posibilidad de generar la fórmula en la hoja desde VBA. Pero lo cierto es que queremos trabajar con esta función sin acudir a la hoja en ningún momento, simplemente utilizar el formulario y los parámetros que hayamos incluido para calcular la edad de una persona.

Aunque esta función no existe en VBA como tal, podemos invocarla a través del método EVALUATE, aunque eso lo iremos viendo en el caso particular que nos ocupa.

Vamos a imaginar que tenemos un formulario con un cuadro de texto (textbox1) en el que debemos incluir la fecha de nacimiento, un botón de comando para ejecutar la macro y otro cuadro de texto (textbox2) en el que vamos a mostrar la edad completa:

CALCULAR LA EDAD EN UN FORMULARIO

Para calcular la edad vamos a incluir en modulo asociado al botón de comando el siguiente código:

Private Sub CommandButton1_Click()
'Definimos variables
Dim validarfecha As Boolean
Dim hoy As String
Dim f_nac As String
Dim año As Double, mes As Double, dia As Double
'Trabajamos con el formulario1
With UserForm1
'Cada vez que ejecutemos la macro vaciaremos el textbox1
.TextBox2 = Empty
'Si no existe fecha o el dato no es una fecha o está mal escrita, activamos mensaje y salimos el cálculo
validarfecha = IsDate(.TextBox1.Value)
If .TextBox1.Value = Empty Or validarfecha = False Or Len(.TextBox1.Value) > 10 Then
MsgBox ("DEBES INTRODUCIR UNA FECHA Y VERIFICAR QUE EL FORMATO SEA EL ADECUADO"), vbExclamation, "CONTROL"
Exit Sub
End If
'Si la fecha es mayor que la fecha actual, activamos mensaje y salimos el cálculo
If CDate(.TextBox1.Value) > Date Then
MsgBox ("LA FECHA NO PUEDE SER MAYOR QUE EL DÍA ACTUAL"), vbExclamation, "CONTROL"
Exit Sub
Exit Sub
End If
'Indicamos la fecha de hoy con formato mm/dd/aaaa y lo componemos en un string
hoy = (Month(Date) & "/" & Day(Date) & "/" & Year(Date))
'Indicamos la fecha de hoy con formato mm/dd/aaaa y lo componemos en un string
f_nac = (Month(.TextBox1.Value) & "/" & Day(.TextBox1.Value) & "/" & Year(.TextBox1.Value))
'Evaluamos la función Datedif para año, mes y día
año = Evaluate("DATEDIF(""" & f_nac & """,""" & hoy & """,""Y"")")
mes = Evaluate("DATEDIF(""" & f_nac & """,""" & hoy & """,""YM"")")
dia = Evaluate("DATEDIF(""" & f_nac & """,""" & hoy & """,""MD"")")
'Pasamos el string con los años, meses y días de nuestra edad actual al textbox2
.TextBox2 = año & IIf(año = 1, " año", " años") & ", " & mes & IIf(mes = 1, " mes", " meses") & " y " & dia & IIf(dia = 1, " dia", " días")
End With
End Sub

Es importante tener en cuenta que la función reconoce la fecha con formato mm/dd/aaaa por lo que debemos especificar esto tanto para la variable que contiene la fecha actual “hoy” como para la que contiene la fecha de nacimiento “f_nac”. Esto lo podemos solucionar componiendo un string con la fecha en el orden indicado.

En el cuadro de texto de la fecha de nacimiento el formato es el habitual: días, meses y años. Si necesitáis introducir los datos con otro formato, tendréis que modificar la macro en los dos string creados para que la función lea adecuadamente la información.

Luego debemos adaptar la función para trabajar con variables y evaluarla con el método Evaluate. Importante el uso de las comillas.

El resultado es el siguiente (calculado sábado 22 de Julio de 2017 a las 23:22 horas):

CALCULAR LA EDAD EN UN FORMULARIO1

Y el resultado es el correcto (y también lo es que me voy haciendo más viejo). El formulario me muestra información completa de la edad que tengo en el momento de ejecutar el código.

He incluido en la macro varios controles: si no existe fecha, si la fecha está mal escrita o si es mayor que el día actual. Si sucede alguna de estas cosas, mostrará un mensaje y proceso finalizará.

Según configuraciones regionales las fechas tendrán formatos distintos, sin embargo, creo que adaptando la macro a meses, días y años funcionará en todos los lugares (siempre que escribamos la fecha de nacimiento con día, mes y año.

Pues esto ha sido todo, espero que os sea de utilidad a la hora de crear formularios o de poner en práctica la función Datedif en VBA.

Descarga el archivo de ejemplo pulsando en: CALCULAR LA EDAD EN UN FORMULARIO DE EXCEL

 
¿Te ha resultado de interés?, puedes apoyar a Excel Signum con una pequeña donación.

Donate Button with Credit Cards

¡¡Muchas gracias!!

EXPORTAR DATOS SELECCIONADOS DE UN LISTBOX A OTRO LISTBOX EN OTRO FORMULARIO

Hace unos días recibí una consulta sobre formularios, la petición en concreto era sobre la necesidad de pasar la información seleccionada en varios listbox de un formulario a los mismo listbox pero en otro formulario.

Además, pedía que aunque se seleccionasen listbox diferentes, se pasase la misma información al segundo formulario y sin duplicar los datos.

Aunque puede parecer una consulta sencilla, la especificación de poder seleccionar cualquier item en cualquier listbox y que la información no se duplique durante el proceso, hacen que requiera un desarrollo a medida.

El post anterior, en el que trataba acerca de cargar datos en un listbox y realizar consultas y filtros con SQL y ADO, ya formaba parte de esta consulta, solo que no quería publicar un post demasiado extenso cuando se puede hacer en dos partes y bien explicado 🙂

Por lo tanto, vamos a utilizar el formulario del post: CARGAR DATOS EN LISTBOX Y REALIZAR BÚSQUEDAS CON ADO Y CONSULTAS SQL que cargaba los datos que previamente habíamos seleccionado a través de los criterios indicados en un buscador, por ejemplo todos los nombres que contienen una “A”.

EXPORTAR DATOS SELECCIONADOS DE UN LISTBOX A OTRO LISTBOX EN OTRO FORMULARIO1

Ahora lo que se pide es pasar los items que queramos seleccionar a un segundo formulario (para nosotros userform2). Por ejemplo así:

EXPORTAR DATOS SELECCIONADOS DE UN LISTBOX A OTRO LISTBOX EN OTRO FORMULARIO2

Como podéis ver, seleccionamos en una ocasión el nombre, en otra la asignatura y en otra la calificación.

Para poder exportar esta selección debemos incluir un botón de comando y pegar el siguiente código:

Private Sub CommandButton2_Click()
'Declaramos las variables
Dim i As Integer, j As Integer, n As Integer
Dim Lista As MSForms.ListBox
Dim nLista As MSForms.ListBox
Dim Control As Control
'Contamos el número de Listbox en el formulario
For Each Control In Me.Controls
If TypeName(Control) = "ListBox" Then
Lbox = Lbox + 1
End If
Next
'Primer bucle: recorremos todos los formularios
For j = 1 To Lbox
Set Lista = Me.Controls("Listbox" & j)
'Segundo bucle: por cada formulario, recorremos los item que contiene
'y detectamos el item seleccionado.
For i = 0 To Lista.ListCount - 1
If Lista.Selected(i) = True Then
'Tercer bucle, volvemos a recorrer todos los items
' y si existen varios items seleccionados en la misma fila (misma persona)
'desmarcamos todos menos el primero (evitando así duplicados).
For n = j + 1 To Lbox
Set nLista = Me.Controls("Listbox" & n)
If nLista.Selected(i) = True Then nLista.Selected(i) = False
Next n
'Pasamos los datos seleccionados al formulario 2
UserForm2.ListBox1.AddItem Me.ListBox1.List(i)
UserForm2.ListBox2.AddItem Me.ListBox2.List(i)
UserForm2.ListBox3.AddItem Me.ListBox3.List(i)
UserForm2.ListBox4.AddItem Me.ListBox4.List(i)
UserForm2.ListBox5.AddItem Me.ListBox5.List(i)
End If
Next i
Next j
'Mostramos formulario 2
UserForm2.Show
End Sub

Una vez pulsado el botón, se muestra el formulario 2 con los datos que hemos seleccionado. Es decir, realiza la tarea correctamente.

EXPORTAR DATOS SELECCIONADOS DE UN LISTBOX A OTRO LISTBOX EN OTRO FORMULARIO3

Pero ¿qué pasaría si seleccionamos para un mismo item (o persona) varias informaciones?, en lógica si el código importa todo lo seleccionado … ¡duplicaría la información!

Pero esto se soluciona con la siguiente parte del código: donde indicamos que si un ítem ha sido seleccionado varias veces, solo tenga en cuenta la primera de ellas, de esta forma no duplicaremos la información:

For n = j + 1 To Lbox
Set nLista = Me.Controls("Listbox" & n)
If nLista.Selected(i) = True Then nLista.Selected(i) = False
Next n

Os he dejado el código muy comentado para que sea sencillo comprender cómo funciona. Espero que os resulte interesante y os sea de utilidad 🙂

Por supuesto, también está la macro del ejercicio anterior, necesaria para cargar los listbox y hacer las búsquedas.

Por cierto, tanto en este post, como en el anterior, el formulario se abre con el evento Workbook.Open, es decir, en el momento que abrimos el archivo se carga automáticamente el formulario. Es posible que si tenéis activada la seguridad en las macros, en el momento de abrir genere un error. Esto se soluciona guardando el archivo y volviéndolo a abrir, o con un on error resume next (pero no me gusta abusar de este recurso).

Descarga el archivo de ejemplo pulsando en: EXPORTAR DATOS SELECCIONADOS DE UN LISTBOX A OTRO LISTBOX EN OTRO FORMULARIO

CARGAR DATOS EN LISTBOX Y REALIZAR BÚSQUEDAS CON ADO Y CONSULTAS SQL

Aunque estoy preparando varios post sobre análisis estadístico de los datos, hoy trataré sobre algo totalmente diferente, los listbox en formularios y la posibilidad de utilizar ADO y las consultas de SQL para buscar y filtrar información.

Vamos seguidamente con un ejemplo para ilustrar el ejercicio. Utilizaré el listado de alumnos que usé para el post de las funciones matriciales, este:

CARGAR DATOS EN LISTBOX Y REALIZAR BUSQUEDAS CON ADO Y CONSULTAS SQL

Y ahora vamos a construir un sencillo formulario en el que vamos a incluir 5 listbox en los que mostraremos la información de la hoja ALUMNOS y también un cuadro de texto (textbox) y un botón de comando para realizar las búsquedas:

Ahora vamos utilizar el siguiente código VBA que vamos a pegar en el evento click del botón de búsqueda, luego lo iremos comentando:

Private Sub CommandButton1_Click()
'Definimos las variables
Dim Dataread As ADODB.Recordset, obSQL As String
Dim cnn As ADODB.Connection, MiLibro As String
Dim Control As control, Nombre As String
'Vaciamos todos los Listbox
For Each control In Me.Controls
If TypeName(Control) = "ListBox" Then
Control.Clear
End If
Next
'grabamos el dato a buscar, si no hay dato la variable Nombre es nula
Nombre = IIf(UCase(Me.TextBox1.Value) = vbNullString, IsNull(Me.TextBox1.Value), UCase(Me.TextBox1.Value))
'Creamos la instrucción SQL según los parámetros que nos interesan, en este caso, el nombre
'y los diferentes carácteres comodín y el operador "like"
obSQL = "SELECT [ALUMNOS$].* " & _
"FROM [ALUMNOS$] " & _
"Where [ALUMNOS$].[NOMBRE] like " & "'%" & Nombre & "%'"
'Guardamos el nombre del libro activo para utilizarlo en la conexión ADO
MiLibro = ActiveWorkbook.Name
'Dejamos el cuadro de búsqueda vacío después de iniciar la consulta
Me.TextBox1.Value = vbNullString
'Iniciamos la conexión ADO
Set cnn = New ADODB.Connection
With cnn
.Provider = "Microsoft.Jet.OLEDB.4.0"
.ConnectionString = "DATA SOURCE=" & Application.ActiveWorkbook.Path + "\" & MiLibro
.Properties("Extended Properties") = "Excel 8.0"
.Open
End With
'Procedemos a grababar los datos de la consulta
Set Dataread = New ADODB.Recordset
With Dataread
.Source = obSQL
.ActiveConnection = cnn
.CursorLocation = adUseClient
.CursorType = adOpenForwardOnly
.LockType = adLockReadOnly
.Open
End With
Do Until Dataread.EOF
'Pasamos la información a cada ListBox a través del recordset
With UserForm1
.ListBox1.AddItem Dataread("ID")
.ListBox2.AddItem Dataread("NOMBRE")
.ListBox3.AddItem Dataread("CLASE")
.ListBox4.AddItem Dataread("ASIGNATURAS")
.ListBox5.AddItem Dataread("CALIFICACIONES")
End With
Dataread.MoveNext
Loop
'Liberamos y cerramos variables
Dataread.Close: Set Dataread = Nothing
cnn.Close: Set cnn = Nothing
End Sub

Con esta macro podremos realizar consultas a través de lo que indiquemos en el cuadro de búsqueda del formulario (textbox1) o lo que es lo mismo, en la variable “Nombre”.

Pero vamos explicando poco a poco el código. Para borrar o limpiar los datos que van a contener los listbox durante las sucesivas búsquedas tenemos que utilizar el siguiente proceso.

For Each control In Me.Controls
If TypeName(Control) = "ListBox" Then
Control.Clear
End If
Next

Una vez que tenemos los listbox libres de datos ya podemos iniciar la consulta SQL:

obSQL = "SELECT [ALUMNOS$].* " & _
"FROM [ALUMNOS$] " & _
"Where [ALUMNOS$].[NOMBRE] like " & "'%" & Nombre & "%'"

Me gustaría comentar que aquí utilizamos el dato contenido en la variable “Nombre”, importante para poder utilizar el operador Like y por lo tanto, comodines en nuestra consulta.

Cuando la información del cuadro de texto está vacía, simplemente no mostrará nada en los listbox, eso es porque he introducido mediante una condición que si el dato de búsqueda es vacío, entonces es nulo (y por eso no muestra nada).

Nombre = IIf(UCase(Me.TextBox1.Value) = vbNullString, IsNull(Me.TextBox1.Value), UCase(Me.TextBox1.Value))

Podríamos quitar la condición y entonces al pulsar “Buscar” y cargaríamos todos los datos en los listbox, pero creo que así es más funcional.

En la parte condicional de la sentencia SQL, estamos indicando mediante el uso de caracteres comodín, que se busquen los nombres que empiecen por la información escrita en el textbox.

"Where [ALUMNOS$].[NOMBRE] like " & "'" & Nombre & "%'"

Por ejemplo, todos los nombre que empiecen por “MA”:

CARGAR DATOS EN LISTBOX Y REALIZAR BUSQUEDAS CON ADO Y CONSULTAS SQL2

Si queremos extraer los nombres que acaban en “A”, el código sería así:

"Where [ALUMNOS$].[NOMBRE] like " & "'%" & Nombre & "'"

Y el resultado este:

CARGAR DATOS EN LISTBOX Y REALIZAR BUSQUEDAS CON ADO Y CONSULTAS SQL3

Y si quisiéramos que se buscase el nombre a partir de cualquier fragmento de texto, simplemente colocaríamos “%” a ambos lados de la variable “Nombre”:

"Where [ALUMNOS$].[NOMBRE] like " & "'%" & Nombre & "%'"

y podríamos realizar búsquedas más abiertas, por ejemplo, todos los nombres que contengan “AL” (independientemente si está delante, en el centro o al final). Este es el resultado:

CARGAR DATOS EN LISTBOX Y REALIZAR BUSQUEDAS CON ADO Y CONSULTAS SQL4

Como podéis observar, la clave está en saber utilizar los caracteres comodín correctamente en la sentencia SQL. Es algo sencillo pero hay que tener especial cuidado con la posición de las comillas simples y los espacios.

Por último, ya sabéis que para este tipo de método es necesario activar la referencia Microsoft ActiveX Data Object 2.8 Library en el editor de VBA.

En el archivo de descarga, la búsqueda de los nombres está condicionada a que contengan parte del dato contenido en el buscador.

Descarga el archivo de ejemplo pulsando en: CARGAR DATOS EN LISTBOX Y REALIZAR BÚSQUEDAS CON ADO Y CONSULTAS SQL