Ordenar datos dentro de un ListBox

Ordenar datos dentro de un ListBox

Excel Macros VBA

A veces, por los motivos que sean, se presenta la necesidad de ordenar datos dentro de un ListBox. Es posible que queramos tenerlos en un determinado orden para después procesarlos o, simeplemente, porque nos resulte mas fácil identificar los elementos en una determinada ordenación.

Vamos a ver aquí, mediante un sencillo ejemplo, como implementar unas rutinas para mover elementos arriba o abajo dentro de la la lista.

Creación de un UserForm

El primer paso será crear un UserForm que nos sirva para desarrollar el ejemplo. Será un UF muy sencillo con los elementos básicos:

  • Un ListBox en el que estáran los datos a ordenar
  • Un botón para subir una posición el elemento seleccionado
  • Otro botón para bajar una posición el elemento seleccionado
  • Un botón para cerrar el UF
  • Añadiremos otro botón que utilizará el FileSystemObject para poder cargar nombres de ficheros en el ListBox y así tener datos susceptibles de ser ordenados

El UF nos debe quedar algo así:

Ordenar datos dentro de un ListBox

Para poder reproducir el ejemplo, los nombres que he asignado son los siguientes:

  • UserForm: UF_OrdenarListBox
  • ListBox: Lst_Ficheros
  • Botón Seleccionar ficheros: Btn_SelFichero
  • Botón Subir: Btn_Subir
  • Botón Bajar: Btn_Bajar
  • Bot´ón Eliminar: Btn_Eliminar
  • Botón Salir: Btn_Fin

Como podréis ver, todo un derroche de imaginación.

ListBox de varias columnas

Para hacer el ejemplo mas genérico, el ListBox creado tiene dos columnas (propiedad ColumnCount = 2). De esta forma veremos como reordenar todos los datos de las diferentes columnas.

En la primera columna, se carga el nombre del fichero y en la segunda, la ruta completa del mismo.

Programación Btn_SelFichero

Para poder ordenar datos dentro de un ListBox, lo primero que necesitamos es tener datos en el mismo.

Para nuestro ejemplo, vamos a cargar esos datos usando nombres de ficheros y, para ello, nos serviremos del FSO.

El código será el siguiente:

Private Sub Btn_SelFichero_Click()
    Dim fd As FileDialog
    Dim FicherosSel As Integer
    Dim RutaCompleta As String
    Dim PosFinRuta As Integer
    Dim Fichero As String
    Dim Indice As Integer
    Dim i As Integer
    
    Set fd = Application.FileDialog(msoFileDialogFilePicker)
    fd.InitialView = msoFileDialogViewList
    fd.AllowMultiSelect = True
    
    FicherosSel = fd.Show

    If FicherosSel = -1 Then
        For i = 1 To fd.SelectedItems.Count
            RutaCompleta = fd.SelectedItems(i)
            PosFinRuta = InStrRev(RutaCompleta, "\")
            Fichero = Right(RutaCompleta, Len(RutaCompleta) - PosFinRuta)
            Indice = Me.Lst_Ficheros.ListCount
            Me.Lst_Ficheros.AddItem
            Me.Lst_Ficheros.List(Indice, 0) = Fichero
            Me.Lst_Ficheros.List(Indice, 1) = RutaCompleta
        Next i
    End If

End Sub

Con este código, al hacer click en el botón de Seleccionar fichero, se nos abrirá una ventana desde la que podremos seleccionar ficheros. Al hacer click en Aceptar en dicha ventana, los nombres de los ficheros seleccionados se cargarán en el ListBox.

Como no es el objeto de este artículo, no explicaré el código. De todas formas, si tienes cualquier duda sobre el mismo, puedes ponerla en el foro:https://informaticamuyfacil.com/ForoExcel/macros-vba/

Programación Btn_Salir

Este es fácil: cierra el UF. Su código es muy sencillo:

Private Sub Btn_Fin_Click()
    Unload Me
End Sub

Programación Btn_Eliminar

Con este botón eliminamos del ListBox el dato seleccionado. Para ello usaremos el siguiente código:

Private Sub Btn_Eliminar_Click()
    If Me.Lst_Ficheros.ListIndex = -1 Or Me.Lst_Ficheros.ListIndex = Me.Lst_Ficheros.ListCount - 1 Then Exit Sub
    
    Me.Lst_Ficheros.RemoveItem (Me.Lst_Ficheros.ListIndex)
End Sub

Como el botón anterior, el código no lo explicaré, pero como ves, es muy sencillo.

Programación Btn_Subir

Aquí empieza la parte interesante. Vamos a ver el código usado para ordenar datos dentro de un ListBox y después veremos el funcionamiento paso a paso.

Private Sub Btn_Subir_Click()
    Dim Fichero As String
    Dim RutaCompleta As String
    Dim Indice As Integer
    
    If Me.Lst_Ficheros.ListIndex = -1 Or Me.Lst_Ficheros.ListIndex = 0 Then Exit Sub
    
    Indice = Me.Lst_Ficheros.ListIndex
    Fichero = Me.Lst_Ficheros.List(Indice, 0)
    RutaCompleta = Me.Lst_Ficheros.List(Indice, 1)
    
    Me.Lst_Ficheros.List(Indice, 0) = Me.Lst_Ficheros.List(Indice - 1, 0)
    Me.Lst_Ficheros.List(Indice, 1) = Me.Lst_Ficheros.List(Indice - 1, 1)
    Me.Lst_Ficheros.List(Indice - 1, 0) = Fichero
    Me.Lst_Ficheros.List(Indice - 1, 1) = RutaCompleta
    
    Me.Lst_Ficheros.ListIndex = Indice - 1
    Me.Lst_Ficheros.Selected(Indice - 1) = True
    
End Sub

El primer paso, será comprobar que haya algún elemento seleccionado y que éste no sea ya el primero, en cuyo caso no puede ir mas arriba. Si se da alguna de estas dos situaciones, se termina la ejecución de la rutina. De esto se encarga la línea

If Me.Lst_Ficheros.ListIndex = -1 Or Me.Lst_Ficheros.ListIndex = 0 Then Exit Sub

Si la propiedad ListInedx es -1, quiere decir que no hay elementos seleccionados.

Si la propiedad ListIndex es 0, significa que el elemento seleccionado es el primero del ListBox. Recuerda que el primer elemento es el 0 y no el 1.

Si el elemento seleccionado no es el primero, se puede reordenar. Esto significa que debemos intercambiar los datos de las posiciones seleccionada e inmediatamente anterior.

La posición del dato seleccionado se carga en la variable Indice en la siguiente línea:

 Indice = Me.Lst_Ficheros.ListIndex

Y los valores de sus columnas en las variables Fichero y RutaCompleta en las dos siguientes:

Fichero = Me.Lst_Ficheros.List(Indice, 0)
RutaCompleta = Me.Lst_Ficheros.List(Indice, 1)

Ahora ya solo nos queda reescribir en la posición Indice los datos de la posición previa (Indice-1), que se hace con el código:

Me.Lst_Ficheros.List(Indice, 0) = Me.Lst_Ficheros.List(Indice - 1, 0)
Me.Lst_Ficheros.List(Indice, 1) = Me.Lst_Ficheros.List(Indice - 1, 1)

Y escribir en la posición Indice-1 los datos que estamos moviendo:

Me.Lst_Ficheros.List(Indice - 1, 0) = Fichero
Me.Lst_Ficheros.List(Indice - 1, 1) = RutaCompleta

Y, para que nos quede bonito, hacemos que la línea que acabamos de subir sea la seleccionada en el ListBox. Para eso son las dos últimas líneas del código:

Me.Lst_Ficheros.ListIndex = Indice - 1
Me.Lst_Ficheros.Selected(Indice - 1) = True

Programación Btn_Bajar

La lógica para bajar es la misma que para subir. Lo único que tendremos que modificar es:

  • La condición para poder bajar un elemento será que no sea el último de la lista
  • Tendremos que intercambiar los datos de la posición Indice por los de la Indice+1.

El código quedaría como sigue:

Private Sub Btn_Bajar_Click()
    Dim Fichero As String
    Dim RutaCompleta As String
    Dim Indice As Integer
    
    If Me.Lst_Ficheros.ListIndex = -1 Or Me.Lst_Ficheros.ListIndex = Me.Lst_Ficheros.ListCount - 1 Then Exit Sub
    
    Indice = Me.Lst_Ficheros.ListIndex
    Fichero = Me.Lst_Ficheros.List(Indice, 0)
    RutaCompleta = Me.Lst_Ficheros.List(Indice, 1)
    
    Me.Lst_Ficheros.List(Indice, 0) = Me.Lst_Ficheros.List(Indice + 1, 0)
    Me.Lst_Ficheros.List(Indice, 1) = Me.Lst_Ficheros.List(Indice + 1, 0)
    Me.Lst_Ficheros.List(Indice + 1, 0) = Fichero
    Me.Lst_Ficheros.List(Indice + 1, 1) = RutaCompleta
    
    Me.Lst_Ficheros.ListIndex = Indice + 1
    Me.Lst_Ficheros.Selected(Indice + 1) = True
End Sub

Como es similar al de subir con solo las consideraciones que indico mas arriba, te dejo el análisis a ti.

Conclusión

Hemos visto que ordenar datos dentro de un ListBox es un proceso con una lógica bastante sencilla que, una vez entendida, no presenta grandes dificultades para su programación.

Espero que este ejemplo te sirva en tus desarrollo.

Si quieres aprender mas, echa un vistazo al listado de entradas de VBA en https://informaticamuyfacil.com/category/excel/macros-vba/

Deja una respuesta