Saltar al contenido

Aporte al foro: Lista desplegable inteligente.


YoelMonsalve

Recommended Posts

publicado

Buenos días comunidad, estoy pensando además de responder las consultas por aquí presentadas, en escribir posts sobre temas diversos pero útiles que por ejemplo a mí me han surgido en trabajos realizados con anterioridad. Esperando dichos recursos puedan serle útiles a alguien más o incluso profundizar en el estudio de ellos (hay bastantes en VBA).

En esta ocasión quiero presentar un ListBox (o más precisamente DropDown) que se rellena "inteligentemente". El problema es básicamente el siguiente: tenemos un conjunto de datos en una hoja de Excel, y queremos que al escribir en una celda de otra hoja, los datos puedan ser seleccionados de entre el conjunto definido en la primera hoja, y por medio de un DropDown, o lista desplegable.

Nota: En este punto quiero aclarar que en lo persona aún me queda clara la diferencia entre controles "DropDown" y "ListBox" de Microsoft, lo que puedo ver es que ListBox es el nombre que reciben cuando son insertados en objetos Userform (formularios), y DropDown cuando se insertan en la hoja de cálculo. Además aclaro a los lectores que no utilicé controls ActiveX porque tampoco tengo totalmente claro sus ventajas con respecto a los controles de formulario tradicionales, o qué ventaja puedan tener los ActiveX sobre estos.

Siguiendo con el tema, una opción sería asociar un rango fijo o estático de datos con el control DropDown pero esta no es la solución satisfactoria si el rango crece o decrece, o cambia completamente como veremos en ampliaciones posteriores de este mismo trabajo. Entonces podemos mediante el uso de macros cargar automáticamente la lista desplegable con datos en forma dinámica. Concretamente, suponga que tenemos un conjunto de valores en la columna A de Hoja1, y queremos que estos sean mostrados como opciones en el DropDown de la Hoja2. Adicionalmente, al clicar en el DropDown, el valor elegido sea transferido a la celda F3 de Hoja 2 (ver el ejemplo del archivo adjunto).

El primer paso sería escribir los datos en la Hoja1, y en la Hoja2 crear un DropDown en este caso llamado "Lst_Nombres". Luego necesitamos dos procedimientos, uno SET_Lst y otro LOAD_Lst. El primero recibe como argumento un objeto de la clase DropDown y se utiliza como para crear una referencia a la lista desplegable que queremos. Básicamente busca entre todos los DropDowns de la hoja activa uno cuyo nombre sea "Lst_Nombres", y si lo encuentra usa una instrucción "Set" de Visual Basic para asociar el argumento recibido con el objeto encontrado. Si no encuentra un DropDown con dicho nombre, entonces asigna Nothing al parámetro pasado.

Sub SET_Lst(ByRef Lst As DropDown)
	    Dim i As Integer, _
        N As Integer
	    Dim LstName As String
    Dim LstExists As Boolean
        
    ' buscando el objeto con el nombre dado, y si lo encuentra lo
    ' asocia a Lst
    LstName = "Lst_Nombres"
    LstExists = False
    For i = 1 To ActiveSheet.DropDowns.Count
        If LCase(ActiveSheet.DropDowns(i).Name) = LCase(LstName) Then
            Set Lst = ActiveSheet.DropDowns(i)
            LstExists = True
            Exit For
        End If
    Next
    If LstExists = False Then
        Set Lst = Nothing
        Exit Sub
    End If
	End Sub
	

Este proceso puede parecer incómodo pero es necesario porque más adelante haremos un llamado a nuestro objeto de lista desplegable desde un módulo de código externo, concretamente del evento Worksheet_Activate(). Entonces, este otro proceso necesita referenciar el objeto DropDown apropiado (la otra otra alternativa sería declarar variables globales con visibilidad desde todos los módulos del proyecto de VBA, pero como se sabe todo enfoque basado en variables globales es básicamente una idea riesgosa).

El otro procedimiento es el que carga los valores en la lista desplegable, y recibe de argumento un objeto DropDown (obtenido justamente con el SET_Lst anterior) cuyos elementos serán rellenados dinámicamente, o sea, en cuánto sea invocado el procedimiento.

	Sub LOAD_Lst(Lst As DropDown)
	    Dim SheetName As String
    Dim S2 As Worksheet
    Dim i As Long, _
        N As Long
    
    ' Nombre de la hoja donde buscar los datos. Puede cambiarlo si es
    ' necesario.
    SheetName = "Hoja1"
    Set S2 = Sheets(SheetName)
    
    ' calculando el número de elementos a cargar
    If S2.[a1] = "" Then
        N = 0
    Else
        If S2.[a2] = "" Then
            N = 1
        Else
            N = S2.[a1].End(xlDown).Row - 1
        End If
    End If
    If N = 0 Then Exit Sub      ' sale, si no hay elementos
    
    ' y rellena la lista
    Lst.RemoveAllItems
    For i = 1 To N
        Lst.AddItem S2.Range("a" & i + 1)
    Next
End Sub

Como se puede ver en los códigos anteriormente mostrados, prefiero declarar objetos Worksheet y asignarles una hoja específica a partir de su nombre, que usar a cada rato instrucciones tan largas como: [tt]Sheets("Hoja1")[/tt]. Si la hoja con dicho nombre no existe, se generará un error en tiempo de ejecución, lo cual se puede corregir pero complicaríamos demasiado el ejemplo (yo sí suelo usar rutinas de gestión de error y comprabación de las variables en todo mi código).

Ahora, si queremos que el ítem seleccionado del DropDown sea pasado a la ceda F3 de Hoja2 simplemente tenemos que añadir un Callback a la lista:

' Callback para del DropDowm.
' Pasa el valor del ítem seleccionado a la celda F3 de "Hoja2"
Sub Lst_Click()
    
    Dim SheetName As String
    Dim S1 As Worksheet
    Dim i As Integer
    
    Dim myLst As DropDown
    
    ' Nombre de la hoja donde buscar los datos. Puede cambiarlo si es
    ' necesario.
    SheetName = "Hoja2"
    Set S1 = Sheets(SheetName)
    
    ' obtiene la lista
    SET_Lst myLst
    
    If Not myLst Is Nothing Then
        i = myLst.ListIndex
        If i > 0 Then
            S1.[f3] = myLst.List(i)
        End If
    End If
    
End Sub

Anteriormente habíamos dicho que si [tt]SET_Lst[/tt] no encuentra el objeto DropDown (porque el usuario lo borró accidentalmente por ejemplo) entones asignará [tt]myLst = Nothing[/tt]. Esta precaución le permite saber al código de [tt]Lst_Click()[/tt] que el myLst no ha sido asignado y por lo tanto no intentará rellenarlo. Aquí vemos otro ejemplo de una buena práctica de programación.

Y finalmente, para que la lista sea rellenadamente automáticamente cada vez que entremos en la Hoja2, hace falta programar el evento [tt]Worksheet_Activate()[/tt] de dicha hoja:

	Private Sub Worksheet_Activate()
	    Dim myLst As DropDown
	    ' fija el objeto myLst de la clase DropDown
    SET_Lst myLst
    
    ' y si tuvo éxito, rellena la lista
    If Not myLst Is Nothing Then
        LOAD_Lst myLst
        ActiveSheet.[f3] = ""
    End If
End Sub

IntelligentList_by_Yoel_v.1.xlsm

publicado

Lo mismo, pero con un control ComboBox ActiveX.

En la hoja Hoja2:

Private Sub Worksheet_Activate()
ComboBox1.List = Sheets("Hoja1").Range("A2:A" & Hoja1.Range("A" & Rows.Count).End(xlUp).Row).Value
End Sub

Private Sub ComboBox1_Change()
[F3] = ""
If ComboBox1.ListIndex > -1 Then [F3] = ComboBox1
End Sub

 

IntelligentList.xlsm

publicado

Muchas gracias marcolios, y la idea es que lo puedas usar este recurso en tus proyectos, si consideras que te puede resultar útil. Y como realmente lleva bastante código, en un post posterior publicaré cómo podemos encapsularlo en una "clase" para mayor comodidad.

Por último, si te resultó interesante, puedes ayudarme con un "me gusta" :)

publicado

Hola YoelMonsalve...

Tengo un problema y no se como resolverlo, quisiera unas ideas de como hacerlo, publique en mi usuario el problema, crees que podrias verlo por favor y darme tus comentarios?

Gracias y cordial saludo

Archivado

Este tema está ahora archivado y está cerrado a más respuestas.

  • 109 ¿Te parecen útiles los tips de las funciones? (ver tema completo)

    1. 1. ¿Te parecen útiles los tips de las funciones?


      • No
      • Ni me he fijado en ellos

  • Ayúdanos a mejorar la comunidad

  • Archivos

  • Estadísticas de descargas

    • Archivos
      188
    • Comentarios
      98
    • Revisiones
      29

    Más información sobre "Cambios en el Control Horario"
    Última descarga
    Por pegones1

    5    1

  • Crear macros Excel

  • Mensajes

    • Buenas tardes, necesito filtrar las filas que contienen determinada palabra (H2), tanto las que las que la contienen en la columna 'Condición A' como las que la contienen en la columna 'Condición B' Si lo hago de forma independiente me funciona el filtrado, pero si quiero que revise en las dos columnas... no lo consigo. ¿Me pueden ayudar? Consulta.xlsx
    • Hola, El texto citado no lo termine de entender, la celda adyacente a Z27 se relaciona con la fila A28 de la hoja VTL1 y el resultado 35 de su ejemplo, se obtiene de la fila 8, así que para hacer algo sin complicaciones use la columna BM para devolver ese valor. Aprovechando los parámetros de discriminación que uso usted para pintar las celdas de la fila, podría usar esos mismos en una fila auxiliar y así obtener un valor que podría usar como criterio en alguna función, sin tener que meterse al terreno de los colores del condicional, porque no son los mismos que los de la paleta de colores en cuestiones de código. ¿Entonces una solución con macros no es de su interés? Si cambia de opinión podría colocar el tema en esa sección, querer formular con los colores del formato condicional tiene sus características específicas, sin mencionar que se actualice "sola". Aunque bueno, todavía es posible que algún maestro o usuario avanzado le pase una solución con alguna función personalizada al ver que usted tiene 365. Si le interesa una idea sencilla podría usar un rango en la fila 5: =SI.ERROR(COINCIDIR(K7,CALCULOS!$B$4:$B$35,0),SI(O(DIASEM(K7)=7,DIASEM(K7)=1),1,0)) Eso le daría la opción de usar: =SUMAR.SI($K$5:$AY$5,">=1",K8:AY8) Saludines
    • Estimados amigos espero estén bien   Tengo este archivo que me ayuda a llevar las horas trabajadas al que necesito añadir en la Hoja5 (HHE) una fórmula que me cuente las Horas trabajadas en Días de Descanso (fines de semana y feriados), actualmente mediante una Regla de Formato Condicional se resaltan en amarillo el Dia de Semana y la Fecha de los Días de Descanso sin embargo el inconveniente se me presenta con los días feriados que cambian de posición de acuerdo a la fecha y cuando el mes comienza en día domingo por lo cual necesito una fórmula que me permita sumar los Días de Descanso cuando la Fecha que le corresponda este resaltada en Amarillo la sintaxis sería más o menos esta para la primera semana del mes de Enero de 2025: =SI('VTL1'!$I$7=AMARILLO;'VTL1'!$I8;0) + SI('VTL1'!$J$7=AMARILLO;'VTL1'!$J8;0) + SI('VTL1'!$K$7=AMARILLO;'VTL1'!$K8;0) + SI('VTL1'!$L$7=AMARILLO;'VTL1'!$L8;0) + SI('VTL1'!$M$7=AMARILLO;'VTL1'!$M8;0) + SI('VTL1'!$N$7=AMARILLO;'VTL1'!$N8;0) + SI('VTL1'!$O$7=AMARILLO;'VTL1'!$O8;0) Y así sucesivamente para el resto de las semanas, con los datos actuales el resultado esperado para la primera semana (I8:O8) sería 9 horas mientras que para el mes (Fila8) el resultado esperado seria 35 horas estos resultados deben reflejarse en la Celda “$Z7” de la Hoja5 (HHE) de modo tal que una vez haya completado la totalidad de la fórmula para el resto de las semanas del mes la pueda correr de Z27 hasta Z42 VTL - HHE_101128.xlsx
    • Hola, veo que tienes 365, así que esta forma funcionará   Almacen.xlsx
  • Visualizado recientemente

    • No hay usuarios registrado para ver esta página.
×
×
  • Crear nuevo...

Información importante

Echa un vistazo a nuestra política de cookies para ayudarte a tener una mejor experiencia de navegación. Puedes ajustar aquí la configuración. Pulsa el botón Aceptar, si estás de acuerdo.