保留表单中的类模块

时间:2017-01-24 07:50:45

标签: excel vba excel-vba userform

假设我想在Excel VBA中制作自行车设计师程序。我有一个类对象(cBike),它有一些默认设置。现在我想在将自行车存放到数据库之前制作一个可用于更改这些设置的表单(如图中的那个)。用于存储的方法(子)位于cBike

Example of a userform for designing a bicycle.

我可以将对象保存为表单代码中的公共变量,如下所示:

Public objBike As cBike 
Public Sub StoreBikeToDatabase()   
 'database storing code goes here 
End Sub

虽然这样可行,但我看到很多人反对使用公共(全球)变量。我不太清楚为什么,除了如果你有太多的全局变量,你的代码将是一团糟。

或者我可以忘记该对象,并使用不同表单控件中的值,而不是类模块cBike的属性。然而,这似乎是一个笨拙的解决方案。

我的问题是:如果有的话,上述哪种解决方案最好?如果没有,那么我该怎么做呢?

更新 我强烈建议您阅读接受的答案,然后再深入了解答案。这两个答案都有一些很棒的想法,而且他们的帖子附加了一些全面的代码示例,可以用于其他类似我的问题。

2 个答案:

答案 0 :(得分:4)

表单本身就是一个类,所以我建议在表单中创建一个私有属性来保存你的Bike对象。然后,您可以通过Property Set例程将现有的Bike对象传递给表单/类。

如果需要由表单中的多个例程访问,则在表单级别声明Bike成员/属性没有问题。仅当整个项目需要使用该对象时,才应使用全局/公共变量(在模块中声明)。

'Private Member of this Form/Class
Private mBike As cBike

'Pass the existing object into this Form/Class
Public Property Let Bike(ByVal obj As cBike)

    Set mBike = obj

End Property

您可以通过声明cBike的属性来有效地在表单控件和类之间创建动态链接:

Private WithEvents mTextBox1 As MSForms.TextBox

Public Property Set TextBox1(ByVal obj As MSForms.TextBox)

    Set mTextBox1 = obj

End Property

这意味着如果文本框的值发生变化,则无需继续将其传递给类。您将需要一个Microsoft Forms 2.0对象库的引用集

答案 1 :(得分:3)

另一种方法是让Bike可编辑。 Bike类将包含BikeEditor,它是用于编辑自行车对象的用户表单。这是自行车类型的示例,但其他自行车属性可以以类似的方式完成。对于BikeType,使用了一个包裹TypeOfBikeEnum的类。

  

自行车

Private m_editor As BikeEditor
Private m_bikeType As BikeType

Private Sub Class_Initialize()
    Set m_editor = New BikeEditor
    Set m_bikeType = New BikeType
End Sub

Public Property Get TypeOfBike() As BikeType
    Set TypeOfBike = m_bikeType
End Property

Public Property Set TypeOfBike(ByVal vNewValue As BikeType)
    Set m_bikeType = vNewValue
End Property

Public Sub Edit()
    m_editor.Initialize Me
    m_editor.Show
End Sub
  

BikeType

Public Enum TypeOfBikeEnum
    [_First]
    Unknown = 1
    MountainBike = 2
    StreetBike = 3
    OfficeBike = 4
    MoonBike = 5
    [_Last]
End Enum

Private m_type As TypeOfBikeEnum

Private Sub Class_Initialize()
    m_type = Unknown
End Sub

Public Property Get TypeValue() As TypeOfBikeEnum
    TypeValue = m_type
End Property

Public Property Let TypeValue(ByVal vNewValue As TypeOfBikeEnum)
    m_type = vNewValue
End Property

Public Function GetBikeTypeNames() As VBA.Collection
    Dim enumVal As Long, name As String
    Set GetBikeTypeNames = New VBA.Collection
    For enumVal = TypeOfBikeEnum.[_First] To TypeOfBikeEnum.[_Last]
        name = GetBikeTypeName(enumVal)
        If name <> "" Then _
            GetBikeTypeNames.Add name, CStr(enumVal)
    Next enumVal
End Function

Public Function GetBikeTypeName(typeOfBikeValue As TypeOfBikeEnum) As String
    Select Case typeOfBikeValue
        Case TypeOfBikeEnum.Unknown
            GetBikeTypeName = "Unknown"
        Case TypeOfBikeEnum.MountainBike
            GetBikeTypeName = "MountainBike"
        Case TypeOfBikeEnum.StreetBike
            GetBikeTypeName = "StreetBike"
        Case TypeOfBikeEnum.OfficeBike
            GetBikeTypeName = "OfficeBike"
        Case TypeOfBikeEnum.MoonBike
            GetBikeTypeName = "MoonBike"
        Case Else
            GetBikeTypeName = ""
    End Select
End Function
  

BikeEditor

Private m_bikeToEdit As Bike

Public Sub Initialize(bikeToEdit As Bike)
    Set m_bikeToEdit = bikeToEdit
    Dim bikeTypeName
    For Each bikeTypeName In m_bikeToEdit.TypeOfBike.GetBikeTypeNames
        Me.bikeTypesComboBox.AddItem bikeTypeName
    Next
    Me.bikeTypesComboBox.ListIndex = m_bikeToEdit.TypeOfBike.TypeValue - 1
End Sub

Private Sub CancelCommandButton_Click()
    Unload Me
End Sub

Private Sub SaveCommandButton_Click()
    If Me.bikeTypesComboBox.ListIndex > -1 Then
        m_bikeToEdit.TypeOfBike.TypeValue = Me.bikeTypesComboBox.ListIndex + 1
    End If
    Unload Me
End Sub
  

模块

Sub test()
    Dim bk As Bike
    Set bk = New Bike

    Dim bt As BikeType
    Set bt = New BikeType
    bt.TypeValue = OfficeBike

    Set bk.TypeOfBike = bt
    bk.Edit
End Sub