2014-04-29 39 views
3

我需要列出一个类的所有私有变量。是这样的:如何通过VBA中的类属性循环

变量的类:

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

子是retruns所有的变量名:

For Each classVariable In clsMyClass 
    Msgbox classVariable.Name 
Next 

结果:

varOne 
varTwo 
varThree 
varFour 

我发现在这个论坛的解决方案但只适用于VB.NET,不适用于VBA。无论如何,我可以在VBA中做到这一点?

在此先感谢。


什么用下面的代码的问题:

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 

这是cls_Utilitario类代码:

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 

当我删除括号中的代码如下因素在Me.Form参数:

Set objColecao = obj_Utilitario.ColecaoForm(Me.Form) 

它让我继续运行代码,但它显示运行时错误2455(无效的引用...) 什么现在?任何想法?

在此先感谢。


这是迄今为止cls_Ativo类代码:

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 

,这就是我想要的窗体模块中要做到:

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 

当我打电话obj_Ativo.Campo,它只是允许我通过arg_Item作为参数,并表明它不会返回任何值,就好像它是一个Let pro perty。但如果它确实是一个Let属性,它应该允许我将第二个参数作为参数传递。

我想要的是在类中的所有变量与不同类型的变量而不是私有变量的集合对象。

在此先感谢。

+1

thouse操作的要点是什么?也许它会更好地存储你的值[字典](http://stackoverflow.com/questions/915317/does-vba-have-dictionary-structure)(而不是单独的变量)与'键=变量名称'和' item = varaible value'? –

+2

VBA不提供该类型的“反射”功能。要做到这一点,唯一的方法就是解析类的源代码。 –

+0

嗨Simoco和蒂姆。我打算将类变量与比较名称的表单域相链接。表单中的每个字段(文本和组合框)将在类中具有相同名称的变量。我想要的是将存储在类变量中的值直接关联到表单域(文本/组合框)。 –

回答

2

对于第二个问题,我认为你不必传递整个表单。只有通过控件才可以。

Set objColecao = obj_Utilitario.ColecaoForm(Me.Controls) 

然后在函数中不要忘记用'New'关键字初始化Collection对象。

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 
+0

hi Dee。我做了你告诉我要做的所有更改,但是当我运行代码时,会显示运行时错误否424,表示在“For Each item In objColecao”行中需要一个对象。 “obj_Utilitario.ColecaoForm(Me.Controls)”不会按预期的方式返回“Set objColecao = obj_Utilitario.ColecaoForm(Me.Controls)”行中的任何集合。为什么?请尽可能在代码中再看一下代码?干杯。 –

+0

hi Dee。在进入ColecaoForm函数代码后,我发现一个没有用的集合对象。我删除它,并... bazinga!非常感谢你的帮助。 –

+0

我很乐意提供帮助。 – dee

5

除了大卫的建议,你也可以看看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 

唯一要注意的是,你仍然不能检查的直接成员clsTest的实例 - 它必须由表单上的控件名称驱动。