Autofiltro, combo y listbox

19/06/2006 - 04:13 por klomkbock | Informe spam
Hola de nuevo,

Posiblemente sea abusar mucho el hacer dos consultas seguidas, pero estoy
enfrascado en una aplicacion que empieza a eternizarse, y uno de los
principales flecos que me quedan es el de la velocidad. Asi que he
decidido arriesgame a una incorreccion. Espero que no moleste a nadie, y
si es asi le pido disculpas de antemano.

Tengo un formulario con un combobox que se rellena con registros unicos de
un campo elegido en funcion de un optionbutton(entre seis optb), y que a
la vez rellena un litbox con las coincidencias segun se pulsa el teclado
en el combo. Funciona aceptablemente bien con pocos registros, pero cuando
el nº es grande (pej: 10.000), le cuesta bastante. He intentado usar
autofiltros en funcion del criterio elegido en el combo para que la
busqueda sea con menos registros, pero a pesar de probar numerosas formas
(casi todas ellas sacadas del foro) no lo consigo. Posiblemente se deba a
que no los aplico en el evento/momento adecuado (aparte de que no acabo de
comprender su sintaxis), he probado en change del combo, pero posiblemente
entre en "conflicto" con los "pulsos" (es un suponer) del teclado y por
eso no da resultado.

A continuacion expongo los codigos que creo intervienen en el proceso. Son
unos cuantos, pero quizas sea la unica forma de mostrarlo en condiciones.
Por cierto, una buena parte estan desarrollados a partir de codigos de
respuestas de expertos ( HM, KL, ..) en el foro. Muchas gracias de nuevo,
y espero no haberoslos desgraciado mucho.

-Codigos

'' He añadido la eñe, el punto y la coma (creo)
Private Sub cmbCriterio_KeyDown(ByVal KeyCode As MSForms _
.ReturnInteger, ByVal Shift As Integer)
Application.ScreenUpdating = False
Select Case KeyCode
Case vbKeyReturn, vbKeyEscape
SendKeys "{Esc}"
Case vbKeyBack
If Pulsos > 0 Then Pulsos = Pulsos - 1
Case 32, 46, 48 To 57, 65 To 90, 97 To 122, 241
Pulsos = Pulsos + 1
End Select
Application.ScreenUpdating = True
End Sub



Private Sub cmbCriterio_Change()
With lstSeleccionar: Num = 0: .Clear: .ColumnCount = 4
LlenarLista
txtNroLibros = .ListCount: End With
End Sub



Private Sub optTitulo_Click()
lstSeleccionar.Clear: Num = 0
Pulsos = 0: Patron = ""
strCombo = "b2:b": rngOrd = "b"
RellenarCombo
cmbCriterio.SetFocus
End Sub




Private Sub optAutor_Click()
lstSeleccionar.Clear: Num = 0
Pulsos = 0: Patron = ""
strCombo = "c2:c": rngOrd = "c"
RellenarCombo
cmbCriterio.SetFocus
End Sub

-

Private Sub RellenarCombo()
Dim Unicos As New Collection
Application.ScreenUpdating = False
With Worksheets("Listado")
Y = .Range("a65536").End(xlUp).Row

''' strCombo y rngOrd voy a cambiarlos a los optButton directamente:
'If optTitulo = True Then
' strCombo = "b2:b": rngOrd = "b"
'ElseIf optAutor = True Then
' strCombo = "c2:c": rngOrd = "d"
'ElseIf optGenero = True Then
' strCombo = "d2:d": rngOrd = "e"
'ElseIf optTema = True Then
' strCombo = "e2:e": rngOrd = "f"
'ElseIf optPais = True Then
' strCombo = "f2:f": rngOrd = "g"
'ElseIf optHermano = True Then
' strCombo = "g2:g": rngOrd = "h"
'ElseIf optApellido = True Then
' strCombo = "l2:l": rngOrd = "l"
'End If
If chkOrdenar = True Then _
.Range(.Range("a1"), .Range("l" & Y)).Sort _
key1:=.Range(rngOrd & "1"), header:=xlYes
Set rngCombo = .Range(strCombo & Y)
On Error Resume Next
For Each Celda In rngCombo
If Trim(Celda) <> "" Then Unicos.Add Celda, CStr(Celda)
Next
With cmbCriterio: .Clear: .ListIndex = -1: End With
With lstSeleccionar: .Clear: .ListIndex = -1: End With
For Sig = 1 To Unicos.Count
cmbCriterio.AddItem Unicos.Item(Sig)
Next
End With
Set Unicos = Nothing
Application.ScreenUpdating = True
End Sub



Private Sub LlenarLista()
Dim filH As Long, ac As Single
If Not Pulsos > 0 Then Exit Sub
Patron = Trim(LCase(Left(cmbCriterio, Pulsos)))
Application.ScreenUpdating = False
With Worksheets("Listado")
.Range(.Range("a1"), .Range("l" & Y)).Sort _
key1:=.Range("a1"), header:=xlYes
End With
For Each Celda In rngCombo
With Celda
If Trim(LCase(Left(.Value, Pulsos))) = Patron Then
filH = .Row
With lstSeleccionar
.TextColumn = 1
.AddItem
For ac = 0 To .ColumnCount - 1
.List(Num, ac) = Range("a" & filH & ":d" & filH)(ac + 1).Value
Next ac
Num = Num + 1
End With
txtNroLibros = lstSeleccionar.ListCount
End If
End With
Next
Application.ScreenUpdating = True
End Sub

En cualquier caso muchas gracias
Un saludo y hasta pronto
Ivan

Preguntas similare

Leer las respuestas

#1 klomkbock
20/06/2006 - 00:44 | Informe spam
Hola de nuevo, quizas he pecado, como en el mensaaje anterior, de dar poca
informacion, dando por supuesto que todo el mundo iba a entenderme.
Disculpas de nuevo.

Los datos para rellenar el combo y el listbox se sacan de una hoja con los
siguientes campos, empezando en la columna "A" y acabando en la "L":

NºFicha<=>Titulo<=>Autor<=>Genero<=>Tema<=>Pais autor<=>Quien lo tiene <=>
<=>Observaciones<=>Editorial<=>Fecha edicion<=>Nombre autor<=>Apellidos autor

Lo que hace es rellenar el listbox con los datos de las 4 primeras
columnas (NºFicha, Titulo, Autor y Genero) pero que coinciden en el campo
de criterio de busca correspondiente segun se escribe en el combobox
(previamente rellenado con los datos del campo espcificado segun unos
botones de opcion),

o sea, p. ej. si esta selecionado el boton de opcion "Pais", y empiezo a
escribir por ej. una E, aparecen en el listbox los campos citados de los
libro de los escritores de los paises que empiecen por e, y asi
sucesivamente.

Pensandolo bien creo que no debe ser posible el uso de autofilter por la
misma condicion cambiante del criterio, que al fin y al cabo seria en si
mismo una especie de filtro, pero al no restringir el rango en que buscar
no agiliza el codigo.


Si a alguien se le ocure algo y puede echar una mano se lo agradezco.

Un saludo y hasta pronto
Ivan
Respuesta Responder a este mensaje
#2 Héctor Miguel
20/06/2006 - 04:25 | Informe spam
hola, Ivan !

[ciertamente que] cuando la rapidez es 'objeto de preocupacion'... los objetos 'collection' NO son 'la mejor opcion'
-> para el llenado de listas y combos 'filtrados' segun criterios, y con bases de datos de chorrocientos mil registros :-((
-> esta la alternativa de sustituir los objetos collection por objetos dictionary
se requiere establecer una referencia en el proyecto de macros [vba -> herramientas / referencias]...
a la biblioteca de objetos 'Microsoft Scripting Runtime'
-> existe tambien la opcion de usar los filtros avanzados -> hacia 'otra' hoja [creo que con esta es con la que ganas rapidez] ;)

en el siguiente ejemplo, he usado una hoja 'oculta' [de nombre y de propiedad visible] :))
-> en el rango 'A1:D1' he copiado los mismos titulos que la hoja 'listado'
-> la columna 'E' esta vacia y en el rango 'F1:F2' voy 'manejando' los criterios para el filtrado
[en este caso, la celda 'F1' tiene el mismo titulo [pais] que la hoja listado y en la celda 'F2' voy 'metiendo' el criterio del combo ;)

en el modulo de codigo del formulario [mismos nombres de tus controles] ==Private Sub cmbCriterio_Change()
lstSeleccionar.Clear
Worksheets("oculta").Range("f2") = cmbCriterio & "*"
LlenarLista
txtNroLibros = lstSeleccionar.ListCount
End Sub
Private Sub LlenarLista()
With Worksheets("oculta")
Worksheets("listado").Range("a1").CurrentRegion.AdvancedFilter _
Action:=xlFilterCopy, _
CriteriaRange:=.Range("f1:f2"), _
CopyToRange:=.Range("a1:d1")
With .Range("a1").CurrentRegion
With .Offset(1).Resize(.Rows.Count - 1)
lstSeleccionar.List = .Value
.ClearContents
End With
End With
End With
End Sub

haz unas pruebas y... si cualquier duda [o informacion adicional]... comentas ?
saludos,
hector.

__ la segunda consulta original __
Los datos para rellenar el combo y el listbox se sacan de una hoja con los siguientes campos
empezando en la columna "A" y acabando en la "L":
NºFicha<=>Titulo<=>Autor<=>Genero<=>Tema<=>Pais autor<=>Quien lo tiene <=>
<=>Observaciones<=>Editorial<=>Fecha edicion<=>Nombre autor<=>Apellidos autor
Lo que hace es rellenar el listbox con los datos de las 4 primeras columnas (NºFicha, Titulo, Autor y Genero)
pero que coinciden en el campo de criterio de busca correspondiente segun se escribe en el combobox
(previamente rellenado con los datos del campo espcificado segun unos botones de opcion),
... si esta selecionado el boton de opcion "Pais", y empiezo a escribir por ej. una E
aparecen en el listbox los campos citados de los libro de los escritores de los paises que empiecen por e, y asi sucesivamente.
Pensandolo bien creo que no debe ser posible el uso de autofilter por la misma condicion cambiante del criterio
que al fin y al cabo seria en si mismo una especie de filtro, pero al no restringir el rango en que buscar no agiliza el codigo.
Si a alguien se le ocure algo y puede echar una mano se lo agradezco.
Respuesta Responder a este mensaje
#3 klomkbock
20/06/2006 - 16:26 | Informe spam
Hola Hector Miguel, como siempre muchas gracias.

No he podido probarlo todavia, pero tiene buena pinta y creo que va a
cambiar bastante mis esquemas.

En cuanto lo pruebe, si veo que me atasco mucho, vuelvo a darte un toque
con las dudas.

Muchas gracias de nuevo.

Un saludo y hasta pronto.
Ivan
Respuesta Responder a este mensaje
#4 klomkbock
21/06/2006 - 02:29 | Informe spam
Hola de nuevo, Hector Miguel

Como no podia ser menos, tenia que volver por aqui. He estado probando el
codigo y me han surgido varios problemas. Paso a intentar explicartelos:

Al principio me ha dado un error que (pido mil disculpas por no acordarme
de cual) creo que era indice fuera del intervalo. Creo que se resolvio
introduciendo la expresion:

If .Rows.Count < 2 Then Exit Sub
antes de:
With .Offset(1).Resize(.Rows.Count - 1)

Aqui parecia empezar a funcionar y en la hoja oculta me colocaba los
titulos de "a1:d1", bordes a este rango hasta un numero de filas igual al
de "listado", pero con las celdas vacias (supongo por clearcontents) y en
f2 me ponia el contenido visible del combo. El listbox no se ha rellenado.

Luego he hecho unas cuantas pruebas que he considerado podian resolver el
fallo (abajo te pongo una, probablemente bastante sin sentido) pero sin
resultado.

En no se muy bien que momento, creo que cuando he intentado asignarle una
variable al campo de extraccion, me ha aparecido el error 1004 con el
aviso de:

"El rango de extraccion tiene un nombre inexistente o no permitido".

A partir de aqui, y a pesar de haber ido deshaciendo casi todo, me ha
seguido dando ese error, incluso cambiando de libro para las pruebas.

Lo mas curioso es que cuando he vuelto a poner tu codigo original (solo
con el "If .Rows.Count < 2 Then Exit Sub" añadido) ha vuelto a funcionar
igual que al principio, pero a la tercera o cuarta prueba ha vuelto a
aparecer el dichoso error y no consigo encontrar/entender la causa.

Tambien es verdad que aunque el uso del filtro avanzado lo comprendo, su
uso combinado con currentregion y resize, aunque creo intuirlo, no acabo
de verlo claro (no las he usado nunca). Quizas este metiendo la pata por
esta causa.

Bueno, disculpame por este rollo y si puedes seguir ayudandome te lo
agradezco. Voy a seguir indagando esta via a ver lo que encuentro.

En cualquier caso muchas gracias.
Un saludo y hasta pronto
Ivan

Aqui pongo una de las pruebas que he hecho, aunque posiblemente un poco
desquiciada. Lo que no corresponde a tu codigo va como comentario:

Private Sub cmbCriterio_Change()
lstSeleccionar.Clear
' If Not Pulsos > 0 Then Exit Sub
' Patron = Trim(LCase(Left(cmbCriterio, Pulsos)))
' Application.ScreenUpdating = False
' With Worksheets("Listado")
' .Range(.Range("a1"), .Range("l" & Y)).Sort _
' key1:=.Range("a1"), header:=xlYes
' End With
' For Each Celda In rngCombo
' With Celda
' If Trim(LCase(Left(.Value, Pulsos))) = Patron Then '_
Worksheets("oculta").Range("f2") = cmbcriterio '=Patron & "*"
' End With
' Next
LlenarLista
txtNroLibros = lstSeleccionar.ListCount
End Sub
Private Sub LlenarLista()
With Worksheets("oculta")
Worksheets("Listado").Range("a1").CurrentRegion.AdvancedFilter _
Action:=xlFilterCopy, _
CriteriaRange:=.Range("f1:f2"), _
CopyToRange:=.Range("a1:d1")
With .Range("a1").CurrentRegion
' If .Rows.Count < 2 Then Exit Sub
With .Offset(1).Resize(.Rows.Count - 1)
lstSeleccionar.List = .Value
.ClearContents
End With
End With
End With
End Sub
Respuesta Responder a este mensaje
#5 Héctor Miguel
21/06/2006 - 06:40 | Informe spam
hola, Ivan !

1) el error 1004 'avisando' que "El rango de extraccion tiene un nombre inexistente o no permitido"...
sigifica que los titulos en el 'area de extraccion' [Worksheets("oculta").Range("a1:d1")] han sido 'borrados' :-((

2) la 'razon' ?... es que el codigo propuesto NO tiene 'preparacion/prevencion/...' para el -posible- caso de que...
[en 'algun momento']... -> NO se encuentren elementos 'coincidentes' con los criterios de filtrado -?-
con lo que el 'siguiente' listado estaria compuesto por... CERO elementos :-(
y -seguramente- el uso de -> .Offset(1).Resize(.Rows.Count - 1) 'aplicado' al -> .Range("a1").CurrentRegion
este ocasionando la 'perdida' de los titulos [necesarios] en dicha 'area de extraccion' :))

3) la -posible- solucion ?...
a) 'conserva' la linea que agregaste... -> If .Rows.Count < 2 Then Exit Sub antes de: With .Offset(1).Resize(.Rows.Count - 1)
b) ELIMINA [o marca] la linea con el -> .ClearContents [tampoco es necesaria, ya que la siguiente vez se sbre-escribe] :))

comentas 'que mas'... leva apareciendo a la propuesta ?
saludos,
hector.

__ consulta original __
... probando el codigo... me han surgido varios problemas...un error... creo que era indice fuera del intervalo
... se resolvio introduciendo la expresion: If .Rows.Count < 2 Then Exit Sub antes de: With .Offset(1).Resize(.Rows.Count - 1)
... parecia empezar a funcionar y en la hoja oculta me colocaba los titulos de "a1:d1"... hasta un numero de filas igual al de "listado"
... pero con las celdas vacias (supongo por clearcontents) y en f2... el contenido visible del combo. El listbox no se ha rellenado.
... creo que cuando he intentado asignarle una variable al campo de extraccion, me ha aparecido el error 1004 con el aviso de:
... "El rango de extraccion tiene un nombre inexistente o no permitido".
... de aqui, y a pesar de haber ido deshaciendo casi todo, me ha seguido dando ese error, incluso cambiando de libro para las pruebas.
... curioso... cuando he vuelto a poner tu codigo original (solo con el "If .Rows.Count < 2 Then Exit Sub" a#adido)
ha vuelto a funcionar... pero a la tercera o cuarta prueba ha vuelto a aparecer el... error y no consigo encontrar/entender la causa.
... aunque el uso del filtro avanzado lo comprendo, su uso combinado con currentregion y resize, aunque creo intuirlo
... no acabo de verlo claro (no las he usado nunca). Quizas este metiendo la pata por esta causa.
... pongo una de las pruebas que he hecho... Lo que no corresponde a tu codigo va como comentario:
Private Sub cmbCriterio_Change()
lstSeleccionar.Clear
' If Not Pulsos > 0 Then Exit Sub
' Patron = Trim(LCase(Left(cmbCriterio, Pulsos)))
' Application.ScreenUpdating = False
' With Worksheets("Listado")
' .Range(.Range("a1"), .Range("l" & Y)).Sort _
' key1:=.Range("a1"), header:=xlYes
' End With
' For Each Celda In rngCombo
' With Celda
' If Trim(LCase(Left(.Value, Pulsos))) = Patron Then '_
Worksheets("oculta").Range("f2") = cmbcriterio '=Patron & "*"
' End With
' Next
LlenarLista
txtNroLibros = lstSeleccionar.ListCount
End Sub
Private Sub LlenarLista()
With Worksheets("oculta")
Worksheets("Listado").Range("a1").CurrentRegion.AdvancedFilter _
Action:=xlFilterCopy, _
CriteriaRange:=.Range("f1:f2"), _
CopyToRange:=.Range("a1:d1")
With .Range("a1").CurrentRegion
' If .Rows.Count < 2 Then Exit Sub
With .Offset(1).Resize(.Rows.Count - 1)
lstSeleccionar.List = .Value
.ClearContents
End With
End With
End With
End Sub
Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente Respuesta Tengo una respuesta
Search Busqueda sugerida