Lo que vamos a ver es algo más que un truco, pero no llega a utilidad, así que lo incluyo en esta "sección" de ejemplos o consejos de cómo hacer las cosas con los controles del Visual Basic.
No es nada del otro mundo el efecto que se consigue, pero puede haber circunstancias en las que nos pueden servir.
Sin ir más lejos en el programilla ese que tengo de los códigos postales (ver sección Gratisware), se podría aplicar esto que voy a explicar para mantener sincronizados las listas de las poblaciones con la de los códigos postales.Las pruebas que he realizado han sido con listbox que no está clasificados, ya que con estos la cosa se complica más de la cuenta y aunque se puede hacer, no me he puesto en ello.
Las posibilidades que he tenido en cuenta son las siguientes:
- Dos listbox sin "multiselección"
- Un listbox multiselect y otro normal
- Dos listbox multiselect
Realmente he creado unas rutinas (o procedimientos) que se encargan del trabajo, aunque sincronizar el contenido de dos ListBox normales, es decir que no permitan selección múltiple, es relativamente fácil, vamos a ver el código para hacerlo antes de pasar a la parte algo más engorrosa de los que permiten múltiple selección.
Private Sub List1_Click() Static YaEstoy As Boolean 'Sincronizar el List1 con el List2 If Not YaEstoy Then YaEstoy = True List2.ListIndex = List1.ListIndex List2.TopIndex = List1.TopIndex YaEstoy = False End If End Sub Private Sub List2_Click() Static YaEstoy As Boolean 'Sincronizar el List2 con el List1 If Not YaEstoy Then YaEstoy = True List1.ListIndex = List2.ListIndex List1.TopIndex = List2.TopIndex YaEstoy = False End If End Sub Private Sub List1_Scroll() 'Sincronizar también el primer item mostrado en la lista List2.TopIndex = List1.TopIndex End Sub Private Sub List2_Scroll() 'Sincronizar también el primer item mostrado en la lista List1.TopIndex = List2.TopIndex End SubComo comprobarás, el código a usar en cada uno de los ListBox es el mismo, lo que cambia es el "orden" en que se sitúan los List1 y List2.
El truco está en que al pulsar en un elemento, se asigne en el otro ListBox el mismo elemento seleccionado.
Además de seleccionar el mismo elemento, se asigna la propiedad TopIndex para que se muestre en la parte superior el mismo elemento en ambos ListBox.
Por otro lado se comprueba también el evento Scroll, éste evento se produce cada vez que se mueve la barra de desplazamiento, por tanto aquí también se asignan en el otro ListBox el elemento que está arriba.Ni que decir tiene que los dos listbox deben tener el mismo número de elementos, si no es así, no tiene sentido la sincronización.
Vamos a ver lo que habría que hacer si alguno de los dos ListBox tiene asignada la propiedad MultiSelect a algún valor diferente de Ninguno.
Private Sub List3_Click() 'Sincronizar el List4 con el List3 SincListBox List3, List4 End Sub Private Sub List4_Click() 'Sincronizar el List3 con el List4 SincListBox List4, List3 End Sub Private Sub List3_Scroll() 'Sincronizar también el primer item mostrado en la lista List4.TopIndex = List3.TopIndex End Sub Private Sub List4_Scroll() 'Sincronizar también el primer item mostrado en la lista List3.TopIndex = List4.TopIndex End SubComo ves el código a usar en el evento Scroll es el mismo que para los ListBox normales, pero para sincronizar el que se haga Click en uno de los ListBox, usamos un procedimiento que se encargará de sincronizar y seleccionar los mismos elementos en ambas listas.
Además de este procedimiento, se usan otros dos, para quitar la selección de un ListBox y otro que se encargará de seleccionar en un ListBox los mismos elementos que haya en otro.
Pero mejor vemos el código:' Private Sub SincListBox(elListOrig As Control, elListDest As Control) Static EnListBox As Boolean 'Sincronizar el elListDest con el elListOrig If Not EnListBox Then EnListBox = True 'Desmarcar los elementos seleccionados QuitarListSelected elListDest 'Marcar en el 1º ListBox los seleccionados del 2º PonerListSelected elListOrig, elListDest 'Posicionar el elemento superior elListDest.TopIndex = elListOrig.TopIndex EnListBox = False End If End Sub Private Sub QuitarListSelected(unList As Control) 'Quitar los elementos seleccionados del listbox indicado 'Parámetros: ' unList el List a controlar ' Dim i& With unList 'Sólo hacer el bucle si permite multiselección If .MultiSelect Then For i = 0 To .ListCount - 1 .Selected(i) = False Next End If End With End Sub Private Sub PonerListSelected(elListOrig As Control, elListDest As Control) 'Marca en el ListDest los elementos seleccionados del ListOrig ' 'Los dos listbox deben tener el mismo número de elementos ' Dim i& 'Por si no tienen los mismos elementos On Local Error Resume Next With elListOrig For i = 0 To .ListCount - 1 elListDest.Selected(i) = .Selected(i) Next End With Err = 0 End SubRealmente el procedimiento que hace el "trabajo duro" es PonerListSelected y este procedimiento vale igualmente para ListBox que puedan seleccionar varios elementos como los que sólo permiten que se seleccione uno sólo, aunque si los dos listbox no permiten múltiple selección es más corto usar el código mostrado al principìo, ya que no hay que hacer ningún bucle.
Por otra parte, se podrían unir los dos procedimientos QuitarListSelected y PonerListSelected, sobre todo si van a tener muchos elementos, así nos ahorramos hacer dos bucles, esto es lo que habría que hacer:
Private Sub ListSelected(elListOrig As Control, elListDest As Control) 'Marca en el ListDest los elementos seleccionados del ListOrig ' 'Los dos listbox deben tener el mismo número de elementos ' Dim i& 'Por si no tienen los mismos elementos On Local Error Resume Next With elListOrig For i = 0 To .ListCount - 1 'Si el origen está seleccionado... If .Selected(i) Then elListDest.Selected(i) = .Selected(i) Else 'sino, quitar la posible selección elListDest.Selected(i) = False End If Next End With Err = 0 End SubPara usarlo sólo habría que cambiar esto en el SincListBox, mejor dicho: así quedaría esta subrutina:
Private Sub SincListBox(elListOrig As Control, elListDest As Control) Static EnListBox As Boolean 'Sincronizar el elListDest con el elListOrig If Not EnListBox Then EnListBox = True 'Poner en el ListDest los mismos que en ListOrig ListSelected elListOrig, elListDest 'Posicionar el elemento superior elListDest.TopIndex = elListOrig.TopIndex EnListBox = False End If End SubEspero que te pueda ser de utilidad. Pronto pondré otros truquillos para usar con los listbox, por ejemplo: mover un elemento de una posición a otra o crear una serie de rutinas para copiar los elementos seleccionados de un listbox y poder pegarlos en otro, además de eliminar los seleccionados, etc. Todo ello usando PopUp menús y esas chorradillas... en cuanto los "desligue" de la utilidad en la que lo tengo y lo ponga por sí sólos...
Si quieres ver los listados para probar esto, pulsa en este link (sincListBox.zip 2.45 KB)