在表单中保留 Class 模块
Preserve Class Module in form
假设我想在 Excel VBA 中制作一个自行车设计师程序。我有一个 Class 对象 (cBike
),它有一些默认设置。现在我想在将自行车存储到数据库之前制作一个可用于更改这些设置的表格(如图中的表格)。存储方法(sub),位于cBike
.
我可以在表单代码中将对象保存为 public 变量,如下所示:
Public objBike As cBike
Public Sub StoreBikeToDatabase()
'database storing code goes here
End Sub
虽然这可行,但我看到很多人反对使用 public(全局)变量。我不太清楚为什么,除了如果你有太多的全局变量,你的代码会很乱。
或者我可以忘记对象,使用来自不同表单控件的值,而不是 Class 模块 cBike
的属性。然而,这似乎是一个笨拙的解决方案。
我的问题是:以上哪种解决方案最好(如果有的话)?如果其中有 none 个,那么我应该怎么做呢?
更新:
我强烈建议您同时阅读已接受的答案和进一步阅读的答案。这两个答案都有一些很棒的想法,dee 的 post 还包含一些全面的代码示例,可用于其他有类似问题的人。
表单本身本质上就是一个 class,因此我建议在表单中创建一个 Private 属性 来保存您的 Bike 对象。然后,您可以通过 属性 Set 例程将现有的 Bike 对象传递到 form/class。
如果需要由表单中的多个例程访问,则在表单级别声明 Bike member/property 没有问题。 Global/Public 只有在对象需要被整个项目使用时才应使用变量(在模块中声明)。
'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 的属性,在表单控件和您的 class 之间有效地创建动态 link:
Private WithEvents mTextBox1 As MSForms.TextBox
Public Property Set TextBox1(ByVal obj As MSForms.TextBox)
Set mTextBox1 = obj
End Property
这意味着如果文本框的值发生变化,您将不需要继续将其传递给 class。您将需要 Microsoft Forms 2.0 对象库的引用集
另一种方法是让 Bike
可编辑。 Bike
class 将包含一个 BikeEditor
这是用于编辑自行车对象的用户表单。这是自行车类型的示例,但其他自行车属性可以用类似的方式完成。对于 BikeType
,使用 class 来包装 TypeOfBikeEnum
。
Bike
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
Module
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
假设我想在 Excel VBA 中制作一个自行车设计师程序。我有一个 Class 对象 (cBike
),它有一些默认设置。现在我想在将自行车存储到数据库之前制作一个可用于更改这些设置的表格(如图中的表格)。存储方法(sub),位于cBike
.
我可以在表单代码中将对象保存为 public 变量,如下所示:
Public objBike As cBike
Public Sub StoreBikeToDatabase()
'database storing code goes here
End Sub
虽然这可行,但我看到很多人反对使用 public(全局)变量。我不太清楚为什么,除了如果你有太多的全局变量,你的代码会很乱。
或者我可以忘记对象,使用来自不同表单控件的值,而不是 Class 模块 cBike
的属性。然而,这似乎是一个笨拙的解决方案。
我的问题是:以上哪种解决方案最好(如果有的话)?如果其中有 none 个,那么我应该怎么做呢?
更新: 我强烈建议您同时阅读已接受的答案和进一步阅读的答案。这两个答案都有一些很棒的想法,dee 的 post 还包含一些全面的代码示例,可用于其他有类似问题的人。
表单本身本质上就是一个 class,因此我建议在表单中创建一个 Private 属性 来保存您的 Bike 对象。然后,您可以通过 属性 Set 例程将现有的 Bike 对象传递到 form/class。
如果需要由表单中的多个例程访问,则在表单级别声明 Bike member/property 没有问题。 Global/Public 只有在对象需要被整个项目使用时才应使用变量(在模块中声明)。
'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 的属性,在表单控件和您的 class 之间有效地创建动态 link:
Private WithEvents mTextBox1 As MSForms.TextBox
Public Property Set TextBox1(ByVal obj As MSForms.TextBox)
Set mTextBox1 = obj
End Property
这意味着如果文本框的值发生变化,您将不需要继续将其传递给 class。您将需要 Microsoft Forms 2.0 对象库的引用集
另一种方法是让 Bike
可编辑。 Bike
class 将包含一个 BikeEditor
这是用于编辑自行车对象的用户表单。这是自行车类型的示例,但其他自行车属性可以用类似的方式完成。对于 BikeType
,使用 class 来包装 TypeOfBikeEnum
。
Bike
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
Module
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