Vincular 2 combobox y 1 listbox con una tabla

Ante todo gracias por tu tiempo y pedirte disculpas por preguntarte directamente pero hace días que ando buscando y no encuentro exactamente lo que necesito.
Verás, tengo un UserForm con dos combobox y un listbox. A parte en una hoja llamada "Pedidos" tengo una tabla ("tabla8") donde voy anotando los pedidos que se realizan. La tabla consta de 15 columnas con los datos necesarios del pedido, donde la columna "A" es la descripción del producto y la "B" la fecha de compra. Evidentemente la tabla va incrementando día a día y además la denominación de los productos ("A") se repite porque se recompra y la fecha de compra ("B") también se repite porque en una fecha se pueden comprar varios productos diferentes.
Quisiera que el Combo1 me listase de la columna "A" los productos y cuando encuentre repetidos me los liste una sola vez. A su vez el Combo2 debería enseñar las fechas de compra del producto seleccionado en el Combo1, tantas como veces se ha comprado ese producto.
En el Listbox debería salir la/s linea/s enteras de la tabla según la selección del Combo1 y Combo2.

1 Respuesta

Respuesta
1
Creo que si entiendo bien lo que pides este código te servirá para hacerte la solución a tu gusto. He creado un botón en la hoja Tabla 8, y usado las filas A para productos y B para fechas (con formato fecha) con cabecera. He usado como columnas auxiliares la C (para los elementos únicos) sin cabecera y la M y N para la selección asociada al primer combo, sin cabecera también. Si esas columnas las tienes ocupadas o no quieres ver los datos intermedios (lo hago así para que veas como funciona) usa otras o incluso otra hoja oculta o nada. Eso lo tendrás que adaptar a tus gustos y necesidades. Igualmente en el listbox incluyo la concatenación de la selección de ambos combos, pero puede que no te sirva así y lo quieras en elementos separados. También puede que quieras limpiar y recalcular los combos con cada nueva selección.
Como digo, tendrás que adaptarlo a tus gustos y necesidades. En la hoja el código asociado al botón solo sirve para mostrar el formulario.
Private Sub CommandButton1_Click()
   UserForm1.Show
End Sub
En el formulario, el código de manejo de los botones y demás es:
Private Type TAux 'datos auxiliares
    crcb1 As String    ' rango del combo 1
    uncb1 As String    ' rango de los valores unicos anteriores
    crcb2 As String
End Type
Private aux As TAux
Private Sub ComboBox1_Change()
    Call BuscaPar(Range(aux.crcb1), Range(aux.crcb2), _
         Range("c" & 1 + ComboBox1.ListIndex), Range("m1"))
    ComboBox2.Clear
    For Each c In Range(Range("m1"), Range("m1").End(xlDown))
        Me.ComboBox2.AddItem (c)
    Next c
End Sub
Private Sub ComboBox2_Change()
Dim fila As Integer
    If ComboBox2.ListIndex > -1 Then 'ha sido un cambio al elegir no por clear
        fila = Range("n" & 1 + ComboBox2.ListIndex).Value
        Range("m" & fila).Select 'solo para ver donde lo encuentra
        ListBox1.AddItem (Range("a" & fila) & _
                        "  con fecha " & _
                        Range("b" & fila))
    End If
End Sub
Sub userform_Initialize()
Dim maxi As Integer
Dim r As Range
Worksheets("Tabla8").Activate
maxi = Range(Range("a1"), Range("a1").End(xlDown)).Rows.Count
aux.crcb1 = "a2:a" & maxi
aux.crcb2 = "b2:b" & maxi
Set r = Range("c1")
Call CopiaDistintos(Range(aux.crcb1), r)
    ComboBox1.Clear
    maxi = Range(Range("c1"), Range("c1").End(xlDown)).Rows.Count
    aux.uncb1 = "c1:c" & maxi
    Set r = Range(aux.uncb1)
    For Each c In r
        Me.ComboBox1.AddItem (c)
    Next c
End Sub
Y en un módulo he includo dos funciones auxiliares para la búsqueda y selección. Podrían ir también en el código del formulario pero me gusta más así.
Sub CopiaDistintos(ro As Range, rd As Range)
Dim c As Range
Dim d As Range
Dim tm As Range
Dim i As Integer
Dim esta As Boolean
i = 0
For Each c In ro
    esta = False
    If tm Is Nothing Then
        Set tm = c
    Else
        For Each d In tm 'no es muy eficiente pero...
            If c = d Then esta = True
        Next d
    End If
    If Not esta Then 'copio al destino la celda
        rd.Offset(i, 0) = c
        Set tm = Union(tm, c)
        i = i + 1
        esta = False
    End If
Next c
End Sub
Sub BuscaPar(ro1 As Range, ro2 As Range, target As Range, rd As Range)
'Busca en ro1 el dato target y añade a rd la pareja de ro2
Dim i As Integer
Dim c As Range
i = 0
For Each c In ro1
    If target = c Then 'añado su pareja
        rd.Offset(i, 0) = Cells(c.Row, ro2.Column)
        rd.Offset(i, 1) = c.Row ' al lado pongo la fila
        i = i + 1
    End If
Next c
End Sub
Bueno espero te sirva.
Gracias prozac por tu tiempo y tu respuesta, pero hay una parte que no entiendo, no se como/donde colocarla y me da error. Es esta del principio
"En el formulario, el código de manejo de los botones y demás es:
Private Type TAux 'datos auxiliares 
    crcb1 As String    ' rango del combo 1 
    uncb1 As String    ' rango de los valores unicos anteriores 
    crcb2 As String 
End Type 
Private aux As TAux"
Da error '9' en tiempo de ejecución: Subíndice fuera del intervalo
¿Podrías indicarme donde/como lo declaro?
Gracias
Toda la parte que llamo en el formulario es código que se sitúa en el formulario no en un módulo. Para ello con en el formulario en la vista de diseño (donde puede añadir y borrarle cosas pincha botón derecho y luego Ver Código...) . Se abrirá la ventana de código del formulario con un sub por defecto que puede ser Form_Click. Quita todo lo que te aparece ahí y pon todo el código que te he indicado como perteneciente al formulario.
Si no puedes, dame tu correo y te envío un fichero de ejemplo.
He seguido tus indicaciones (anteriormente también lo había hecho así) y me sigue indicando el mismo error.
Lo dicho, mi correo [email protected]
Gracias
Te lo envío.
Muchas gracias, tu ejemplo funciona perfecto y es lo que buscaba. Magnífico.
Solo unas cuestiones (sí me permites abusar)
En el mismo formulario tengo otro combo para el mismo listbox, que realiza una búsqueda simple de productos y lista la totalidad de compras del producto seleccionado en el listbox. Claro está en el Initialize del form tengo unas instrucciones para ese combo referentes a donde apuntar para rellenarlo con los productos. La instrucción de ese combo apunta a una tabla de otra hoja (la principal del stock), así compara con la celda de productos de la tabla de pedidos (tabla8) y funciona perfectamente.
Las preguntas serían: ¿Puedo combinar ambas instrucciones en el Initialize y en ese caso cómo? o, ¿Puedo cambiar la instrucción de tu Inicitalize para que tu combo apunte también a la misma tabla de la misma hoja que mi combo? o, ¿Debo crear frames u optionButton para distinguirlos y en el Initialize separar las instrucciones con algo (¿tipo IF) ¿Para cada frame/optionButton? o...?
Gracias de nuevo por tu tiempo y tu paciencia.
Saludos
No estoy seguro de entender bien la cuestión. En principio el procedimiento Initialize del form no es más que un procedimiento que se ejecuta sin ser llamado explícitamente por el usuario (se hace cuando se carga el form). Desde ese punto de vista puedes incluir las instrucciones que quieras dentro de él o llamar a otros subprocedimientos. Por ejemplo si tienes un procedimiento que usas para limpiar un array, lo puedes invocar en el Initialize aunque luego lo uses también en otras partes de tu código.
Entiendo que cuando dices que el combo apunte, te refieres a que tome los valores de la lista que puedan seleccionarse de un sitio concreto. Hay dos maneras. Una es en las propiedad del combo y otra por código añadir elementos. La primiera es más fácil si la lista origen no cambia mientras que la segunda es para cuando la lista cambia, como cuando los valores dependen de otro combo o selección previa. En principio no hay ningún problema en que dos combos distintos tomen los mismos valores para sus listas, lo contrario (al mismo tiempo) es lógicamente imposible. No necesitas que la inicialización de los combos que tomen la misma lista sea al mismo tiempo. Lo puedes hacer cuando quieras, incluso puedes hacer un procedimiento genérico que dado un combo carga una lista de valores. Y luego lo invocas donde te haga falta.
No sé si esto responde a tu pregunta. Ya me dices algo.
Hola prozac
Muchas gracias por tu aclaración y mil disculpas por mi ignorancia, exactamente tus respuestas responden a mis dudas.
Te agradezco mucho tu tiempo y te incluyo en mi lista de expertos favoritos.
Saludos

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas