none
Control Name con string RRS feed

  • 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.

     

     

     

    miércoles, 5 de mayo de 2010 19:09

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
    Wend

    Aqui 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, tiTulo

     

    Atte CJ

    miércoles, 5 de mayo de 2010 21:44

Todas las respuestas

  • Hola Alvaro; a ver si entendí. Si el chk(n) está seleccionado, debe tomar los valores de dos cuadros de textos que tienen el mismo sufijo(n)?

     

    miércoles, 5 de mayo de 2010 21:25
  • Si, esa es la idea. Al final se trata de llamar a una variable en tiempo de diseño, ya sea con el mismo sufijo u otra cosa.
    miércoles, 5 de mayo de 2010 21:33
  • 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
    Wend

    Aqui 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, tiTulo

     

    Atte CJ

    miércoles, 5 de mayo de 2010 21:44
  • 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

    miércoles, 5 de mayo de 2010 22:04
  • Se vé muy bién tu código. Puedes hacerlo 'global' pasándole el nombre del formulario como argumento. Creas la variable (en mi ejemplo se llama frm) y lo haces universal.

    Atte

    CJ

    miércoles, 5 de mayo de 2010 22:12
  • 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.

    miércoles, 5 de mayo de 2010 22:18
  • 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 Sub

    Simplemente 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.

    miércoles, 5 de mayo de 2010 22:27
  • 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

    miércoles, 5 de mayo de 2010 22:38
  • 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);
    this.b2.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]

    miércoles, 5 de mayo de 2010 22:50