Principales respuestas
Control Name con string

Pregunta
-
Hola, tengo una duda.
Quiero realizar una serie de tareas comunes para varios controles, por lo que he he optado por hacerlo con un bucle for each. El problema es que no se como asignar los nombres mediante variables. Lo explico con un ejemplo:
Tengo los siguientes controles:
chk1, chk2,chk3 ... chk20 :checkbox
txt1,txt2, txt3....txt20 :texto con un nombre
txtId1,txtId2,txtId3....txtId20: texto con un Id
La idea es que el sistema, cuando el checkBox esté seleccionado, guarde los valores correspondientes de nombre e id, es decir:
If chk1.Value=true then
Guardar(txtId1,txt1)
End if
Ahora bien, yo habia pensado hacerlo asi:(esta sin terminar)
Dim ctl As Control Dim ctrl As Control Dim contador As Integer contador = 1 For Each ctl In Me.Controls If ctl.Name = ("chk" & contador) Then For Each ctrl In Me.Controls Next contador = contador + 1 Next
El problema es que necesito 3 bucles, y cuanto menos es poco eficiente. Yo lo que quiero saber es si existe una forma de llamar a una variable con un string o integer, algo asi como:
Dim indice as integer
indice=1
Guardar(("txtId" & indice).Value,("txt" & indice).Value)
De forma que "txtId" & indice lo reconozca como la variable de tipo textbox txtId1 por ejemplo.
Respuestas
-
Esto lo tomé del código que genera Microsoft Access al crear el swicthboard.
While (Not (rs.EOF))
Me("Option" & rs![ItemNumber]).Visible = True
Me("OptionLabel" & rs![ItemNumber]).Visible = True
Me("OptionLabel" & rs![ItemNumber]).Caption = rs![ItemText]
Me("img" & rs![ItemNumber]).Visible = True
'cont = cont + 1
rs.MoveNext
WendAqui puedes ver cómo hacer referencia a un control que tiene un sufijo.
Por otro lado, puede ser útil hacer referencia a los controles según su tipo (Controltype).En este fragmento de código, se recorre los controles y si el control es text(109) o combobox(111) y está disponible, lo 'blanquea' y desbloquea.
Private Sub Form_Open(Cancel As Integer)
On Error GoTo unerr
If Not IsNull(Me.OpenArgs) Then
For Each ctl In Me.Controls
If ctl.ControlType = 109 Or ctl.ControlType = 111 Then
If ctl.Enabled = True Then
ctl.Value = ""
ctl.Locked = False
End If
End If
Next...
Fíjate en este segmento; se carga un recordset; en el formulario, los cuadros de texto tienen el mismo nombre que los campos, aunque no estén vinculados a un origen de registro. Se recorre el recordset y se hace referencia al cuadro de texto en el form, de manera de cargar en cada txt el valor del campo; luego cierro recordset, destruye objetos y queda desconectado. La novedad está en que el módulo sirve para todos o casi todos los forms de la aplicación, ya que le pasas como argumento el nombre del form.
...(ojo: SQL SERVER)
...
Set frm = Forms(nForm)
...'refresco los datos en el formulario
For Each fld In rst.Fields
'Debug.Print fld.Name & "/valor=" & fld.Value
Select Case fld.Type
Case adCurrency, adDecimal, adDouble, adNumeric, adSingle
frm.Controls(fld.Name).Value = fld.Value 'Format(Trim(fld.Value), "##,##0.#0")
Case adBigInt, adSmallInt, adInteger
frm.Controls(fld.Name).Value = fld.Value
Case 11
If fld.Type = 11 Then
If fld.Value = "Falso" Then
frm.Controls(fld.Name).Value = 0
Else
frm.Controls(fld.Name).Value = 1
End If
End If
Case 135 And fld.Precision = 16
frm.Controls(fld.Name) = Format(Trim(fld.Value), "hh:mm")
Case Else
frm.Controls(fld.Name).Value = Trim(fld.Value)
End Select
Next
rst.Close
Set rst = Nothing
Editar = True
MsgBox "Registro guardado", vbInformation, tiTuloAtte CJ
- Marcado como respuesta Alvaro Matabuena miércoles, 5 de mayo de 2010 22:05
Todas las respuestas
-
-
-
Esto lo tomé del código que genera Microsoft Access al crear el swicthboard.
While (Not (rs.EOF))
Me("Option" & rs![ItemNumber]).Visible = True
Me("OptionLabel" & rs![ItemNumber]).Visible = True
Me("OptionLabel" & rs![ItemNumber]).Caption = rs![ItemText]
Me("img" & rs![ItemNumber]).Visible = True
'cont = cont + 1
rs.MoveNext
WendAqui puedes ver cómo hacer referencia a un control que tiene un sufijo.
Por otro lado, puede ser útil hacer referencia a los controles según su tipo (Controltype).En este fragmento de código, se recorre los controles y si el control es text(109) o combobox(111) y está disponible, lo 'blanquea' y desbloquea.
Private Sub Form_Open(Cancel As Integer)
On Error GoTo unerr
If Not IsNull(Me.OpenArgs) Then
For Each ctl In Me.Controls
If ctl.ControlType = 109 Or ctl.ControlType = 111 Then
If ctl.Enabled = True Then
ctl.Value = ""
ctl.Locked = False
End If
End If
Next...
Fíjate en este segmento; se carga un recordset; en el formulario, los cuadros de texto tienen el mismo nombre que los campos, aunque no estén vinculados a un origen de registro. Se recorre el recordset y se hace referencia al cuadro de texto en el form, de manera de cargar en cada txt el valor del campo; luego cierro recordset, destruye objetos y queda desconectado. La novedad está en que el módulo sirve para todos o casi todos los forms de la aplicación, ya que le pasas como argumento el nombre del form.
...(ojo: SQL SERVER)
...
Set frm = Forms(nForm)
...'refresco los datos en el formulario
For Each fld In rst.Fields
'Debug.Print fld.Name & "/valor=" & fld.Value
Select Case fld.Type
Case adCurrency, adDecimal, adDouble, adNumeric, adSingle
frm.Controls(fld.Name).Value = fld.Value 'Format(Trim(fld.Value), "##,##0.#0")
Case adBigInt, adSmallInt, adInteger
frm.Controls(fld.Name).Value = fld.Value
Case 11
If fld.Type = 11 Then
If fld.Value = "Falso" Then
frm.Controls(fld.Name).Value = 0
Else
frm.Controls(fld.Name).Value = 1
End If
End If
Case 135 And fld.Precision = 16
frm.Controls(fld.Name) = Format(Trim(fld.Value), "hh:mm")
Case Else
frm.Controls(fld.Name).Value = Trim(fld.Value)
End Select
Next
rst.Close
Set rst = Nothing
Editar = True
MsgBox "Registro guardado", vbInformation, tiTuloAtte CJ
- Marcado como respuesta Alvaro Matabuena miércoles, 5 de mayo de 2010 22:05
-
Perfecto, funciona. No habría probado las opciones Form.Control() y Me() porque en ambas, en la ayuda ponía como parámetro Index, lo cual probé, (y funciona) pasándole como entero el Indice de Tabulación, pero no probé con un string.
También he usado lo que comentas de ControlType e incluso usar la propiedad Tag (Informacion Adicional), que me comentaron en este mismo foro y me ha resultado muy util para Desactivar o hacer no visible partes de un formulario con diferentes tipos de controles.
Un ejemplillo que me ha ahorrado muchas lineas de código y me permite activar y desactivar todos los controles que yo quiera, asi como cambiar el color de fondo (por ejemplo):
For Each ctl In Me.Controls Select Case ctl.ControlType Case acCommandButton '104 If Mid(ctl.Tag, 4, 2) = "NU" Then Debug.Print "Activando " & ctl.Name ctl.Enabled = camposNU ElseIf Mid(ctl.Tag, 4, 2) = "LE" Then Debug.Print "Desactivando " & ctl.Name ctl.Enabled = camposLE End If Case acCheckBox '106 Debug.Print "Activando " & ctl.Name ctl.Enabled = camposLE Case acTextBox '109 If Mid(ctl.Tag, 4, 4) = "Hora" Then ctl.Enabled = False ElseIf Mid(ctl.Tag, 4, 4) = "Dato" Then ctl.Enabled = camposLE ctl.BackColor = colores End If Case acComboBox '111 If Mid(ctl.Tag, 4, 4) = "Dato" Then ctl.Locked = camposNU ctl.BackColor = colores End If End Select Next
-
-
Si, podría hacerlo, aunque le utilizo en un único formulario que es muy complejo (muchos campos, aunque la mayoria se rellanan de forma automatica al introducir un solo dato) asi que le he metido en un private sub en el mismo formulario. En otros casos si que lo usaré.
Al principio era de los de ir desactivando opcion a opcion, textbox a textbox, pero cuando son muchos campos... es un trabajo de chinos,jeje.
-
Hablando de automatizar, tengo el siguiente código, ya creado:
Private Sub txtHorasR(txtHoraE As TextBox, txtHoras As TextBox) Dim HoraSalida As Date If Fechas.ValidarHora(txtHoraE.Value, HoraSalida) Then txtHoraE.Value = Format(HoraSalida, "HH:mm") txtHoras.Value = Format(DateAdd("n", TiempoCarga, HoraSalida), "HH:mm") Else txtHoras.Value = "" txtHoraE.BackColor = vbRed
End If End Sub Private Sub txtHoraE1R_AfterUpdate() txtHorasR txtHoraE1R, txtHoraS1R End Sub Private Sub txtHoraE2R_AfterUpdate() txtHorasR txtHoraE2R, txtHoraS2R End Sub Private Sub txtHoraE3R_AfterUpdate() txtHorasR txtHoraE3R, txtHoraS3R End Sub Private Sub txtHoraE4R_AfterUpdate() txtHorasR txtHoraE4R, txtHoraS4R End SubSimplemente lo que hace es que introduciendo la hora de llegada de un camión, la valida, y en caso de que sea correcta, según el tiempo de carga pone la hora de salida. Si no es correcta pone el campo en rojo. Como eso ocurre en 21 campos, pues al final lo calculo en una función y lo llamo desde las correspondientes.
En C# podías poner el nombre de evento que tu quisieras (en el boton3, no tenia porque ser necesariamente boton3_Click. sino que podia ser directamente boton_Click, asi valdría para todos. No se si en access con vba se puede hacer algo parecido, por no tener tantas lineas todas iguales, o automatizarlo más.
-
No entiendo el planteamiento. Me parece que te refieres a una función o procedimiento en un módulo estandar o procedimiento declarado público en un módulo de formulario.
Pero en cuanto a los eventos, no puedes 'inventar' uno nuevo, hasta donde yo se. Te debes limitar a los eventos disponibles en VBA, sino cuando compiles, te indicará error.Atte CJ
-
Ya creo que no podré hacerlo. Me habia acostumbrado a C#, en el cual el diseñador crea los eventos para los botones, textbox, etc. y aunque les cree el diseñador, el código que genera está en el archivo xxxxx.designer.cs, en el que hay código como este:
this.bModificar.Click += new System.EventHandler(this.bModificar_Click);
Es decir, asigna la acción click del boton bModificar a un evento que vendrá recogido en el método bModificar_Click, con lo cual si se tienen varios botones, se pueden asignar todos al mismo evento, con lo que todos buscan la misma función, por ejemplo:
this.b1.Click += new System.EventHandler(this.b1_Click); this.b2.Click += new System.EventHandler(this.b2_Click);
Para tratar lo que queramos hacer en los botones b1 y b2 se generan sendas funciones b1_Click() y b2_Click, pero si por lo que sea los dos botones hacen lo mismo, podría usar una sola función poniendo:
this.b1.Click += new System.EventHandler(this.boton_Click);
Supongo que Access es mas cerrado que eso y no permite estas cosas. Sería tan sencillo como que en propiedades, en los eventos, donde pone [procedimiento de evento] dejase poner el Nombre del Evento, por ejemplo [boton_Click]
this.b2.Click += new System.EventHandler(this.boton _Click);