在表单中保留类模块

8
假设我想在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

虽然这样做是可行的,但我见过很多人反对使用公共(全局)变量。除了如果你有太多的全局变量,你的代码会变得混乱之外,我不太确定为什么会这样。
或者我可以忘记对象,使用不同表单控件的值,而不是类模块的属性。然而,这似乎是一个有点笨拙的解决方案。
我的问题是:以上哪种解决方案是最好的,如果有的话?如果没有,那我应该怎么办?
更新: 我强烈建议您阅读被接受的答案和dee的帖子。两个答案都有一些很棒的想法,dee的帖子还包含了一些全面的代码示例,可以用于其他类似我的问题的人。

你可以将表单上的三个值和一个 Cancelled 属性转换为属性,由调用代码进行读写,并负责根据需要更新 cBike 对象。 - Rory
这取决于您需要在哪里以及为什么需要存储该数据(在内存中与数据库相对)。如果每次只创建一个类的新实例,编辑属性并保存到数据库,则应该在表单内创建一个privatecBike实例,或在显示表单之前传递已经创建的cBike实例。 - GSerg
我的想法是需要将已经创建的 cBike 实例传递给表单,然后该表单会保留该对象,直到需要存储它。在传递给表单之后,cBike 的属性可能会被表单更改,但在存储到数据库之前。 - Jakob Busk Sørensen
2个回答

4

表单本质上就是一个类,因此建议在表单中创建一个私有属性来保存您的自行车对象。然后通过属性设置程序将现有的自行车对象传递到表单/类中。

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

'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的属性,有效地在表单控件和类之间创建动态连接:

您可以通过以下方式声明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 Object Library 的引用。

谢谢,这似乎比我的想法更聪明。通过一些巧妙的方法,我想这也可以允许控件与 cBike 对象的相应属性之间建立某种连接... - Jakob Busk Sørensen
是的,没错。我已经包含了一个编辑来展示如何完成这个操作。 - Jiminy Cricket
那么,我应该将控件添加为属性而不是变量吗?例如,我不再有一个名为NumberOfGears()的属性与整数相关联,而是将其与文本框相关联?那么,如何获取/设置该属性的值(即文本框的值)呢? - Jakob Busk Sørensen
没错。您可以像操作变量一样获取/设置值,但是与“intVariable =”不同,它将是“TextBox1.Value =”。 - Jiminy Cricket

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
(自行车类型)
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
自行车编辑器
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

1
感谢提供如此全面的指南。我非常喜欢将编辑表单添加到对象本身而不是将对象传递给表单的想法。 - Jakob Busk Sørensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接