4

I need to list all the private variables of a class. something like:

Variables in the class:

Dim varOne as String
Dim varTwo as Integer
Dim varThree as Date
Dim varFour as String

Sub that retruns all the variable names:

For Each classVariable In clsMyClass
     Msgbox classVariable.Name
Next

Result:

varOne
varTwo
varThree
varFour

I found the solution in this forum but only for VB.NET, not for VBA. is there anyway I can do this in VBA?

thanks in advance.


what's the problem with the code below:

Private Sub btnTest_Click()
    Dim obj_Utilitario As cls_Utilitario
    Dim objColecao As Collection
    Dim item As Variant

    Set obj_Utilitario = New cls_Utilitario
    Set objColecao = obj_Utilitario.ColecaoForm(Me.Form)

    For Each item In objColecao
        MsgBox item.Name
    Next item

    Set objColecao = Nothing
End Sub

this is the cls_Utilitario class code:

Public Function ColecaoForm(arg_form As Object) As Collection
    Dim colecao As Collection
    Dim campo As Control

    For Each campo In arg_form.Controls
        With campo
            Select Case .ControlType
                Case acComboBox, acTextBox
                    colecao.Add (.Object)
            End Select
        End With
    Next campo

    Set ColecaoForm = colecao

    Set colecao = Nothing
    Set campo = Nothing
    Set arg_form = Nothing
End Function

when I remove the parentheses in the folowing code in the Me.Form argument:

Set objColecao = obj_Utilitario.ColecaoForm(Me.Form)

it lets me keep on running the code but it shows runtime error 2455 (invalid reference...) what now? any idea?

thanks in advance.


this is the cls_Ativo class code so far:

Option Compare Database
Option Explicit

Private obj_Utilitario As New cls_Utilitario
Private col_Ativo As Collection

Private Const SQL As String = "SELECT tbl_Ativos.codigo_ativo, tbl_Ativos.especificacao FROM tbl_Ativos ORDER BY tbl_Ativos.codigo_ativo;"

Private Sub Class_Initialize()
    Dim registro As Recordset
    Dim campoRegistro As Field
    Dim i As Integer

    Set col_Ativo = New Collection

    Set registro = CurrentDb.OpenRecordset(SQL)

    If (Not (IsNull(registro)) And (registro.RecordCount > 0)) Then
        registro.MoveLast
        registro.MoveFirst

        For i = 0 To registro.Fields.Count - 1
            Set campoRegistro = registro.Fields(i)
            col_Ativo.Add campoRegistro, campoRegistro.SourceField
        Next i
    Else
        Set col_Ativo = Nothing
    End If

    Set registro = Nothing
    Set campoRegistro = Nothing
End Sub

Private Sub Class_Terminate()
    Set col_Ativo = Nothing
    Set obj_Utilitario = Nothing
End Sub

Public Property Get Campo(arg_Item As Variant) As Variant
    Campo = col_Ativo.item(arg_Item)
End Property

Public Property Let Campo(arg_Item As Variant, arg_Valor As Variant)
    Select Case arg_Item
        Case "codigo_ativo"
            If VarType(arg_Valor) = vbString Then
                If ValidaCodigoAtivo(arg_Valor) Then
                    col_Ativo.item(arg_Item) = arg_Valor
                Else
                    MsgBox "O código inserido não é válido."
                End If
            Else
                MsgBox "O código inserido não é um texto."
            End If

        Case "especificacao"
            If VarType(arg_Valor) = vbString Then
                col_Ativo.item(arg_Item) = arg_Valor
            Else
                MsgBox "A especificação inserida não é um texto válido."
            End If
    End Select
End Property

and this is what i want to do in the form module:

Private Sub btnTeste_Click()
    Dim obj_Ativo As cls_Ativo

    Set obj_Ativo = New cls_Ativo

    'Save a text into the collection item "especificacao" using Let property
    obj_Ativo.Campo ("especificacao","texto de exemplo, texto de exemplo...")

    'Return the collection item using Get property
    Msgbox obj_Ativo.Campo ("especificacao")

    Set obj_Ativo = Nothing
End Sub

when i call obj_Ativo.Campo, it just allows me to pass arg_Item as parameter and shows that it will not return any value, as if it were a Let property. but if it were a Let property indeed, it should allow me to pass the second argument as parameter.

what i want is to have a collection object in the class with all the variables with different types instead of private variables.

thanks in advance.

5
  • 1
    what is the point of thouse manipulations? maybe it would be better to store your values in dictionary (instead separate variables) with key=variable name and item=varaible value? Commented Apr 29, 2014 at 23:18
  • 2
    VBA doesn't provide that type of "reflection" functionality. Pretty much the only way to do it is to parse the source code for the class. Commented Apr 29, 2014 at 23:46
  • hi Simoco and Tim. i intend to link the class variables with the form fields comparing the names. each field (text and combobox) in the form will have a variable in the class with the same name. what i want is to associate values stored in the class variables right into the form fields (text/comboboxes). Commented Apr 29, 2014 at 23:53
  • For an example of using a Dictionary object, see here. Commented Apr 30, 2014 at 1:00
  • thanks, David. now, i see it is possible to reach the desired result with this technique. once more, thanks. Commented Apr 30, 2014 at 3:12

2 Answers 2

5

In addition to David's suggestion, you can also look into using CallByName:

Sub Tester()

Dim c As New clsTest

    c.one = 1
    c.two = "two"
    c.three = True

    Debug.Print "Before-----------"
    Debug.Print CallByName(c, "one", VbGet)
    Debug.Print CallByName(c, "two", VbGet)
    Debug.Print CallByName(c, "three", VbGet)

    CallByName c, "one", VbLet, 10
    CallByName c, "two", VbLet, "changed"
    CallByName c, "three", VbLet, False

    Debug.Print "After-----------"
    Debug.Print CallByName(c, "one", VbGet)
    Debug.Print CallByName(c, "two", VbGet)
    Debug.Print CallByName(c, "three", VbGet)

End Sub

clsTest:

Public one As Long
Public two As String
Public three As Boolean

The only thing to note is you still can't examine directly the members of an instance of clsTest - it would have to be driven by the names of the controls on the form.

Sign up to request clarification or add additional context in comments.

Comments

2

To your second question, I think you do not have to pass whole Form. It will be ok if you pass Controls only.

Set objColecao = obj_Utilitario.ColecaoForm(Me.Controls)

Then in the function do not forget to initialize the Collection object with 'New' keyword.

Public Function ColecaoForm(arg_form_controls As Controls) As Collection
    Dim campo As Control

    Set ColecaoForm = New Collection

    For Each campo In arg_form_controls
        If campo.ControlType = acComboBox Or _
           campo.ControlType = acTextBox Then
            ColecaoForm.Add campo
        End If
    Next campo
End Function

2 Comments

hi Dee. i did all the changes that you told me to do but, when i run the code, a runtime error no 424 is shown saying that an object is required in the line "For Each item In objColecao". "obj_Utilitario.ColecaoForm(Me.Controls)" doesn't return any collection in the line "Set objColecao = obj_Utilitario.ColecaoForm(Me.Controls)", as expected. why? could you, please, have another look in the code when possible? cheers.
hi Dee. after stepping into the ColecaoForm function code i found a collection object without use. i removed it and... bazinga! thanks a lot for your help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.