Crear función usando Trim en todos los controles del formulario
En ocasiones me pasa que me dejo espacios antes y después del texto en los controles del formulario, en cuadros de texto, combos, etc.
Me gustaría poder eliminar esos espacios mediante "TRIM" creando una función en un módulo, que pueda llamar en el evento "al cargar" del formulario o en "al activar registro" para así asegurarme que las cadenas de texto de cualquier control del formulario no tienen espacios delante o detrás.
La función debería abarcar todos los controles del formulario o al menos los controles del form cuyo origen del control es la tabla "Libros". El formulario se llama "FormLibros"
Prsonalmente tomaría otro camino, aunque el que apunta Sveinbjorn es correcto, salvo en que hace referencia al Nombre del control y no al contenido del control que es lo que yo interpreto. Dicho esto, haria este Procedimiento, dentro o Fuera del Formulario.
Public Sub QuitaEspaciosIniFin() Strsql = "select titulo, tomovolumen, coleccion, autor, editorial, tipodocumento, categoria, genero, materia, signatura " StrSQL = StrSQL & "FROM LIBROS;" Set Rst = CurrentDb.OpenRecordset(StrSQL, dbOpenDynaset) 'Por pura Rutina, me aseguro que devuelve Registros If Not Rst.EOF And Not Rst.BOF Then Rst.MoveLast Rst.MoveFirst Do While Not Rst.EOF Rst.Edit Rst!TITULO = Trim(Rst!TITULO) Rst!TOMOVOLUMEN = Trim(Rst!TOMOVOLUMEN) Rst!COLECCION = Trim(Rst!COLECCION) Rst!AUTOR = Trim(Rst!AUTOR) Rst!EDITORIAL = Trim(Rst!EDITORIAL) Rst!TIPODOCUMENTO = Trim(Rst!TIPODOCUMENTO) Rst!CATEGORIA = Trim(Rst!CATEGORIA) Rst!GENERO = Trim(Rst!GENERO) Rst!MATERIA = Trim(Rst!MATERIA) Rst!SIGNATURA = Trim(Rst!SIGNATURA) Rst.Update Rst.MoveNext DoEvents Loop End If Rst.Close Set Rst = Nothing End Sub
Optaria por hacer la llamada en el Evento al Cerrar del Formulario, pero se puede hacer desde un Botón u otro procedimiento.
No resalto porquees Obvio que Modifica toda la Tabla, si es que hay espacios.
No he tenido en cuenta los Campos Fecha,,, Mis saludos >> Jacinto
Hola Jacinto
Sí... interpretas bien, me refería al contenido del control, a que no hubiera espacios antes o después del valor que se inserta en cada control.
No he probado la función (aunque seguro que va genial, como todo lo que me propones) pero quería comentarte una cosa...
Mi interés de hacerlo todo lo que pueda con funciones es para de esa manera poder usar en distintos sitios, el mismo código.
Pero para eso la función no puede hacer referencia directa a campos o controles de un formulario concreto, porque si no, no me haría falta una función... podría poner el código que me indicas en algún evento del formulario y evitarme de esa manera la función.
Necesitaría una función que no se refiriera directamente a controles del formulario (Titulo, Coleccion, Autor, etc:) , que usara variables, para así poder usarla donde quisiera y luego ya la llamaría en los eventos concretos de cada formulario.
Si tengo una función genérica tan solo tengo que llamarla desde un evento con una simple línea. Imagínate que tuviera que usar esa función para eliminar los espacios de los controles de 5 formularios diferentes con distintos controles... entonces tendría que crear 5 funciones casi iguales, indicando en cada una los nombres de los controles de cada formulario y no sería muy práctico...
Por eso siempre busco funciones construídas con variables o de otro modo que evite personalizar su código para un form o control concreto, como "DesbloquearControles" o "ControlesNulosEnForm" o "BloqueaBotones" .
Ya me dices si se puede reconstruir la función que me indicas teniendo en cuenta esto que te comento.
Como siempre un saludo y muchísimas gracias por la ayuda
Rafa: Creo que las aclaraciones que te hace Sveinbjorn, son las adecuadas para que la Función que te propone la puedas poner en un Módulo y no hayas de repetirla.
La que yo te propuse si quieres utilizarla para una "Limpieza" general, la pones en un botón porque ciertamente consume recursos de modo innecesario.
Mis saludos >> Jacinto
Hola Jacinto
La verdad es que tu función como bien dices me sirve y mucho para una "limpieza general" ahora que tengo muchos registros y seguro que con espacios en el contenido de los controles.
Luego una vez hecha esa limpieza con tu función, ya podemos usar la función de Sveinbjorn.
Quería saber si en tu función podemos cambiarla y usar una estructura SQL para usar TRIM solo en los campos de la tabla "LIBROS".
Algo así como...
Me.recordsource = "Select TRIM (*) FROM LIBROS
o "Select TRIM (Libros.Titulo) and TRIM (Libros.Autor) y el resto de campos...
o poner directamente el nombre de la consulta en vez de la línea SQL... Ya sé que no vale lo que pongo pero hacerte una idea...
Bueno ya me dices si hay alguna forma mediante SQL de usar TRIM solo en los campos de la tabla "Libros"
Pues Un saludo y gracias por todo
Rafa: Intentando cubrir tu necesidad y a raíz de un comentario constructivo y acertado por supuesto de Sveinbjorn, me he animado a hacer un procedimiento general que quite los espacios Iniciales y Finales de una Tabla, teniendo en cuenta que >>
De entrada tenga en cuenta si el Campo es Autonumérico, que presumo es Entero Largo, Campo Si/No, y dejando la puerta abierta, a que el programador, de acuerdo con la Tabla, excluya de forma explicita 4 campos más. El resultado es el que cito a continuación.
Public Sub QuitaEspaciosIniFin(TablaObjeto As String, Optional ExcluyeCA As String, Optional ExcluyeCB As String, Optional ExcluyeCC As String, Optional ExcluyeCD As String) Dim BytCampo As Byte Dim CampoTabla As String 'Jacinto Trillo Jareño 24/02/2016, para una pregunta de Todoexpertos 'Se supone que si hay un Auto Numérico es de tipo dbLong. 'Los Check Box se excluyen para evitar el Error, y además se deben excluir los Campos Calculados On Error GoTo QuitaEspaciosIniFin_TratamientoErrores Set Rst = CurrentDb.OpenRecordset(TablaObjeto, dbOpenDynaset) 'Por pura Rutina, me aseguro que devuelve Registros If Not Rst.EOF And Not Rst.BOF Then Rst.MoveLast Rst.MoveFirst Do While Not Rst.EOF For BytCampo = 0 To Rst.Fields.Count - 1 CampoTabla = Rst(BytCampo).Name If Rst(BytCampo).Type <> dbLong And Rst(BytCampo).Type <> dbBoolean Then If CampoTabla <> ExcluidoA Then Rst.Edit Rst(CampoTabla).Value = Trim(Rst(CampoTabla)) Rst.Update End If End If Next BytCampo DoEvents Rst.MoveNext Loop End If Rst.Close Set Rst = Nothing MsgBox "Se han quitado los espacios Iniciales y Finales de todos los Campos de la Tabla: " & TablaObjeto, vbInformation, "ESPACIOS DE TEXTO SUPRIMIDOS" QuitaEspaciosIniFin_Salir: On Error GoTo 0 Exit Sub QuitaEspaciosIniFin_TratamientoErrores: MsgBox "Error " & Err & " en Procedimiento.: QuitaEspaciosIniFin de Documento VBA: MdlConsultasYTablas (" & Err.Description & ")", vbCritical + vbOKOnly, "ATENCION" Resume QuitaEspaciosIniFin_Salir End Sub 'QuitaEspaciosIniFin(TablaObjeto................. 'Aqui hago el sondeo de si el Campo es ono Calculado Function EsCampoCalculado(BytCampo As Byte) As Boolean If Rst.Fields(BytCampo).DataUpdatable = False Then EsCampoCalculado = False Else EsCampoCalculado = True End If End Function
Este Procedimiento puede llamarse desde cualquier sitio con
Call QuitaEspaciosIniFin(“TablaEsObligada”, “RestoEsOpcional”)
Lo que no me parece adecuado es llamarlo en un Form_Curret, por ejemplo.
En éste caso concreto, yo lo he hecho en un Botón cuyo código es:
Private Sub BtnQuitaEspacios_Click() Call QuitaEspaciosIniFin("LIBROS", "AñoMasISBN") End Sub
Supongo que como todo será mejorable
Mis saludos a los dos. Rafa y Sveinbjorn
Jacinto
Las prisas algunas veces son compañeras de los errores y éste es uno de los casos.
He cambiado el Nombre de las variables del Procedimiento y no las he trasladado al código que he henviado.
Public Sub QuitaEspaciosIniFin(TablaObjeto As String, Optional ExcluidoA As String, Optional ExcluidoB As String, Optional ExcluidoC As String, Optional ExcluidoD As String)
Es la línea correcta.
Saludos >> Jacinto
Hola Jacinto
MIL, MIL GRACIAS por tu esfuerzo!!!!!
Funciona de maravilla y en todos los registros, lo que me permitirá hacer una limpieza total de toda la BD.
Ahora sí es una función que puedo aplicar a cualquier formulario o hasta en otras bases de datos. Era lo que necesitaba una función como ésta, global.
--------------------------------------------------------------------------------------------------------------------
Te comento solo un detalle por si se puede rematar la faena
Para hacer pruebas he hecho lo siguiente:
He creado 3 registros en el form, TODOS con espacios en el campo "AUTOR"
Si pulso el botón para eliminar espacios desde el registro 1 me los elimina en todos los registros y funciona perfecto... pero...
1\ He observado que si me voy al registro 2 y desde ahí pulso el botón para quitar los espacios, no me los quita del registro 2 y solo si me voy al registro 3 y vuelvo al 2 se me actualiza el campo "AUTOR" sin espacios.
2\ También he observado que si estoy en el registro 3 y apreto el botón, no me elimina los espacios de ese registro y si voy al registro 2 y vuelvo al 3 sigue sin actualizarse el campo sin espacios. Pero a veces sí funciona y eso es lo raro.
En resumen que si apreto el botón en un registro que no sea el 1, a veces me funciona y en otras no... parece aleatorio no lo entiendo.
Haz la prueba exactamente como te indico (con los 3 registros con espacios en "AUTOR" y verás que a veces haciendo lo mismo me quita los espacios y a veces no.
Ya me dices... Un saludo y de nuevo gracias por la función global.
Rafa: Por lo que observo, esos datos "Creo" que aún no están en la Tabla. Es decir:
En el Formulario estoy visualizando el Registro 2. Modifico el cuadro de Texto AUTOR y Le dejo 10 espacios. Pulso el Botón de quitar espacios y no me hará nada, porque ese dato no ha ido a la Tabla. Voy al Registro 3, Modifico el 3 y pulso el Botón.
Me modificará solo el 2 porque el 3 está en datos del Formulario, no en la Tabla.
Mis saludos >> Jacinto
Hola Jacinto
1\ En parte tienes razón:
Solo si cierro el form y lo vuelvo a abrir o cambio de registro, al apretar el botón me elimina los espacios. (al guardarse ya en tabla)
¿Podría poner alguna línea en el form para que se actualizasen los datos al momento en la tabla sin necesidad de cambiar de registro o cerrar y abrir el form para que así al apretar el boton me eliminara los espacios de ese registro? con "Me.Requery" he probado y nada.
-----------------------------------------------------------------------------------------------------------------------------------
Pero creo que aparte de eso que es cierto hay algo más...
Para comprobarlo:
2\ He dejado en "Autor" espacios en 3 registros y sin pulsar el botón... He cerrado el form para asegurarme que la tabla ya tiene los campos guardados con espacios.
He abierto la tabla y he comprobado que los datos con espacios ya están guardados en el campo "Autor"
He vuelto a abrir el form con los 3 registros con espacios en "Autor" y me he ido al reg. 2 y he pulsado el botón y nada, no actualiza el campo APARENTEMENTE!!!
(He observado que si esperas mucho tiempo, como 1 minuto al final me lo actualiza, después del mensaje)
En cambio si abro el form en el reg 1 y pulso el botón me actualiza enseguida todos los registros y me elimina los espacios.
Aquí no es que no se hayan guardado los cambios en la tabla...
Es que el botón por alguna razón trabaja mucho más lento si lo pulso desde el reg. 2 o posteriores que si lo hago desde el 1.
¿Se podría hacer algo sobre esto para que al margen de en qué reg. estoy el botón trabajara igual?
Saludos
Rafa: He hecho algunos ensaos y no noto esa diferencia de velocidades de poceso.
Además he incluido un Me. Requery en la llamada o sea:
Private Sub BtnQuitaEspacios_Click()
Me.Requery
Call QuitaEspaciosIniFin("LIBROS", "AñoMasISBN")
End Sub
He velto ha hacer pruebas y lógicamente el fenómeno de los registros no guardados desaparece.
Justo he probado dejando espacios en el "AUTOR", de los Registros 2, 3 y 4.
Después he probado con el Campo TITULO y no he tenido problemas.
La verdad es que aparte de poner ese Requery, no se que decirte, salvo enviarte la BD que yo tengo. Lo hago ahora. Saludos >> Jacinto
- Compartir respuesta
1 respuesta más de otro experto
Te pongo esto de cabeza, sin probarlo, a ver si la vas ajustando a tus necesidades:
Public Sub subQuitaEspacios(elForm as Form)
Dim ctl as Control
For Each ctl in elForm.Controls
If ctl.ControlType=acTextBox Then elForm.Controls(ctl.Name)=Trim(elForm.Controls(ctl.Name))
Next ctl
End Sub
Y lo llamas así:
Private Sub Form_Load()
subQuitaEspacios Me
End Sub
Se me olvidó un detalle: si tienes un campo autonumérico, tienes que excluirlo para que no te de error, o ignorar ese error con un control de errores.
Hola Sveinbjorn
Sí... Tengo un campo autonumérico "IDLIBROS" y me da error...
¿Podrías indicarme cómo excluirlo?
También me marca como error la línea...
If ctl.ControlType=acTextBox Then
elForm.Controls(ctl.Name)=Trim(elForm.Controls(ctl.Name))
Y por último he visto que lo que me indicas solo me funciona en el registro 1, solo me elimina los espacios de los controles en el registro 1 y no en los demás registros.
Ya me dices
Un saludo
Un par de aclaraciones, deprofundis:
1º/ El código funciona perfectamente, no da error en al linea que dices, a menos que tu hayas escrito algo mal en tu BD (se me ocurre que lo hayas puesto en dos lineas en vez de una. http://www.filebig.net/files/CbVhEiK8SC
Antes de abrir el formulario, fíjate que los campos de la tabla tienen espacios y al abrirlo se eliminan.
2º/ Hace lo que pides: "La función debería abarcar todos los controles del formulario o al menos los controles del form cuyo origen del control es la tabla "Libros""
Si lo pones en "Al cargar", te elimina los espacios en los textbox del registro que se carga (el primero, el último... el que sea)
Si lo pones en "al activar registro", te lo hará cada vez que cambies de registro.
Otra cosa es lo que comentas aquí: "solo me funciona en el registro 1, solo me elimina los espacios de los controles en el registro 1 y no en los demás registros."
Si quieres que te revise todos los registros de la tabla, tienes que trabajar sobre la tabla, no sobre el formulario, como la solución que te propone Jacinto.
3º/ Para no tener en cuenta el campo ID, puedes añadirle esto (forma obvia):
Public Sub subQuitaEspacios(elForm As Form) Dim ctl As Control For Each ctl In elForm.Controls If ctl.ControlType = acTextBox And ctl.Name <> "ID" Then elForm.Controls(ctl.Name) = Trim(elForm.Controls(ctl.Name)) Next ctl End Sub
Si quieres controlar otros tipos, añades sus constantes al If (acComboBox, acListBox)
4º/ Relacionado con el punto 2, hacer la comprobación en toda la tabla cada vez que cargas un registro o te mueves por ellos es una pérdida de recursos. Tendría sentido hacerlo una vez para revisar los datos existentes, pero en las siguientes sólo es necesario comprobar los registros nuevos.
Esto quiere decir que el evento en el que colocar el procedimiento debe ser otro ("antes de actualizar", "al guardar"...) Si tienes un botón para guardar, ese sería el lugar adecuado.
La "ventaja" de mi propuesta es precisamente que la puedes usar con cualquier formulario sin tener que modificarla, como comenta Jacinto, al no estar haciendo referencia directa a los nombres de los objetos.
Hola Sveinbjorn
Tienes razón en Todo!!!
Tu función va genial y ahora estoy seguro... porque me bajé tu ejemplo y funciona perfectamente, perdona.
Pero algo debe haber mal en mi BD porque cuando abro el formulario me salta este mensaje
y luego me subraya esta línea
Se te ocurre qué puedo tener mal para que me salte este mensaje y me subraye la línea...
Ya me comentas y muchas gracias por la ayuda.
Ese error te lo da al intentar editar el autonumérico. En la bd de ejemplo y en el código de la segunda respuesta (punto 3), tienes una forma de evitarlo.
Hola Sveinbjorn
Como bien dices es 100% por culpa del campo "ID" que es autonumérico porque para hacer la prueba lo he pasado a numérico y ya no me da error...
Una vez sé esto lo que no comprendo es por qué si pongo el código como me dices (segunda respuesta punto 3) justamente para evitar el error, me sigue dando error.
Yo pongo lo que me dices para evitar el error que me genera el "ID" autonumérico:
Public Sub subQuitaEspacios(elForm As Form) Dim ctl As Control For Each ctl In elForm.Controls If ctl.ControlType = acTextBox And ctl.Name <> "ID" Then elForm.Controls(ctl.Name) = Trim(elForm.Controls(ctl.Name)) Next ctl End Sub
Pero me sigue saltando el error... "no se puede asignar un valor a este objeto". El caso es que tu código está perfecto.
¿Podríamos ignorar el error que produce el "ID" autonumérico creando un control de errores...? A ver si así evito el problema.
Ya me dices cómo quedaría el control de errores... y con eso cierro el tema y como siempre muy agradecido.
Un saludo
A ver, primero dices que mi BD te funciona (tiene un campo autonumérico llamado "ID"), y luego que el mismo código en la tuya no funciona con tu cmapo autonumérico. La pregunta obvia es ¿tu campo se llama ID? Y si no es así, ¿Modificaste el código para que se adapte a tu BD? A mi me da que no.
Con control de errores, que a estas alturas ya deberías ser capaz de hacerlo tu mismo, sería así:
Public Sub subQuitaEspacios(elForm As Form) On Error Goto sol_err Dim ctl As Control For Each ctl In elForm.Controls If ctl.ControlType = acTextBox Then elForm.Controls(ctl.Name) = Trim(elForm.Controls(ctl.Name)) Next ctl Salida: Exit Sub sol_err: If Err.Number=2448 Then resume next Else Msgbox "Se ha producido el error " & Err.Number & ": " & Err.Description, vbInformation End If End Sub
Hola Sveinbjorn
Dame un voto de confianza :) :)
Sigo diciendo lo mismo:
Tu ejemplo me funciona perfectamente...
Pero el mismo código en mi BD, salta el error 2448 y me subraya en amarillo parte de esta línea:
If ctl.ControlType = acTextBox And ctl.Name <> "ID" Then elForm.Controls(ctl.Name) = Trim(elForm.Controls(ctl.Name))
desde "... elForm.Controls(ctl.Name) = Trim(elForm.Controls(ctl.Name))"
... y SÍ... he modificado el código que me mandas con respecto a mi campo autonumérico. En mi BD el campo se llama "IDLIBRO" y así lo he modificado en la función que me propones.
Public Sub subQuitaEspacios(elForm As Form) Dim ctl As Control For Each ctl In elForm.Controls If ctl.ControlType = acTextBox And ctl.Name <> "IDLIBRO" Then elForm.Controls(ctl.Name) = Trim(elForm.Controls(ctl.Name)) Next ctl End Sub
Lo de arriba es lo que he puesto... como ves, he cambiado tu "ID" por el nombre que yo tengo en el campo autonumérico que es "IDLIBRO" pero sigue dándome error.
Debe haber algo incompatible con ese código en mi BD. En fin ya lo encontraré
Un saludo y gracias por la ayuda
El nombre que tienes que poner es el que tengas en el formulario, no en la tabla, que no tienen por qué coincidir.
Verificado esto, que supongo que sí, igual el error no te lo da el autonumérico.
¿Tendrás algún cuadro de texto cuyo origen de control sea una expresión o algún cuadro que tenga como origen un campo calculado en al tabla?
Si es así (he de suponer que sí, pues sería la única explicación lógica), has de añadir esos campos al If (o usar la versión con el control de errores)
GRACIAS!!! POR FIN encontramos el problema!!
En un principio para el autonumérico tenía distinto nombre en la tabla y en el formulario, en uno se llamaba "IDLIBRO" y en otro "TboxIDLIBRO" pero eso ya lo tuve en cuenta y puse finalmente en las pruebas para tu código "IDLIBRO" tanto en el campo autonumérico de la tabla como en el nombre del control del formulario. En los dos casos en las pruebas lo renombré como "IDLIBRO" para no tener este problema. Por tanto el problema como intuías finalmente no estaba en el autonumérico...
Lo que sí que tengo es un cuadro de texto cuyo origen del control es una expresión.
El cuadro de texto se llama TxtRegActivos.
¿Cómo me quedaría el código si tengo que meter este cuadro de texto en el IF...? Tal vez así:
Public Sub subQuitaEspacios(elForm As Form)
Dim ctl As Control
For Each ctl In elForm.Controls
If ctl.ControlType = acTextBox And ctl.Name <> "TboxIDLIBRO" And ctl.Name <> "TxtRegActivos" Then elForm.Controls(ctl.Name) = Trim(elForm.Controls(ctl.Name))
Next ctl
End Sub
Supongo que como siempre no he acertado... Ya me dices cómo añadir al código el nombre del control cuando puedas.
Un saludo y gracias por no abandonar :-)
Usa la función que tiene el control de errores, te será más fácil y además "portable" para cualquier formulario de cualquier bd.
Yo anidaría los IFs:
If ctl.ControlType = acTextBox Then
If ctl.Name <> "TboxIDLIBRO" OR ctl.Name <> "TxtRegActivos" Then
elForm.Controls(ctl.Name) = Trim(elForm.Controls(ctl.Name))
End If
End If
- Compartir respuesta
"aunque el que apunta Sveinbjorn es correcto, salvo en que hace referencia al Nombre del control y no al contenido del control"... Jacinto, si dices eso es que no has entendido lo que hace el código, je je - Sveinbjorn El Rojo
Diego: Llevas razón, fue una ligereza mía . Al ver ctl.Name no miré bien la lógica del código. Mis saludos y gracias por la observación. Jacinto - Jacinto Trillo Jareño
Usar esa sintaxis tiene la ventaja de hacer el procedimiento "general", sin referenciarlo a unos controles concretos. Tu propuesta se podría modificar fácilmente en ese sentido si usases índices - Sveinbjorn El Rojo
Diego: Este último comentario me ha servido de estímulo para hacer un Procedimiento Publico, que puedes ver en otra contestación a Depro.Mis saludos >> Jacinto - Jacinto Trillo Jareño