excel 有没有一种方法可以设置一个变量一次,然后在多个地方使用它,而不给它模块级的作用域?

n3ipq98p  于 2023-01-10  发布在  其他
关注(0)|答案(3)|浏览(125)

我有一个向集合添加用户窗体控件的循环。
由于在多个地方都需要这个集合,所以我将它推到一个模块中,并在需要时调用它。
这意味着集合只在需要时才在内存中,但这也意味着每次要使用它时都要运行一个循环。
我 * 本 * 可以给出集合模块级范围,并在第一次需要它时创建它。
我本来会运行一次循环,但是集合会一直保存在内存中。
我发现32位Excel的内存限制为1.75Gb(尽管这可以扩展,还有64位版本),VBA Excel是单线程的。
看起来我应该优先考虑处理器效率而不是内存效率,除非我有特殊的需要,这样不仅应用程序会更快,而且可能会更节能。
赋予收集模块级别的作用域会使其容易发生意外更改。
有没有办法创建一次集合,但不给予它模块级的作用域?
更好的是,有没有一种方法可以做到这一点,只有在需要的时候它才在内存中?

33qvvth1

33qvvth11#

我不认为有任何方法可以创建一个比模块小的函数作用域(这似乎是您想要的)。
如果你担心意外的修改,你可以创建一个类来实现一个只读数组。这个类的一个示例可以是模块级的,但是一旦设置了这些项,它们就既不能被修改,也不能被新值替换。
在类模块中:

'Class ROA (Read Only Array)

Private A As Variant
Private initialized As Boolean

Public Property Get Item(i As Long) As Variant
    Item = A(i)
End Property

Public Property Let Items(data As Variant)
    If Not initialized Then
        A = data
        initialized = True
    Else
        Debug.Print "Illegal attempt to modify data"
    End If
End Property

测试代码(在标准代码模块中):

Dim A As ROA

Sub test1()
    Set A = New ROA
    A.Items = Array(3, 1, 4) 'set items once
End Sub

Sub test2()
    test1
    Debug.Print A.Item(0) 'prints 3
    A.Items = Array(5, 6, 7) 'no effect on A
    Debug.Print A.Item(0) 'still prints 3
End Sub

运行test2时,输出为:

3 
Illegal attempt to modify data
 3

当然,你可以创建一个类的新示例并将其赋给A,对象是只读的,变量本身不是,这足以防止意外修改。
上面的代码主要是概念验证。你可以改进它,例如,如果你传递给它的数据不是数组,它会抛出一个错误。你也可以抛出一个错误,而不是在试图更改数据时什么都不做,而不是简单地记录它。此外,您可能希望尝试使用this clever way来使Item()成为默认方法,以便可以只使用A(0)而不是A.Item(0)

laik7k3q

laik7k3q2#

经过一段时间的调整,我想我已经找到了一个方法来做我想做的事情。虽然我不确定这是否是最好的方法...

Option Explicit

Function testColl(ByVal uf As Object, ByVal createColl As Boolean) As Object

Static Coll As New Collection
Dim ctrl As Object

If createColl = True Then
    For Each ctrl In uf.Controls
        Coll.Add ctrl
    Next ctrl
End If

Set testColl = Coll

End Function

以及按钮来测试它。

Option Explicit

Private Sub CommandButton1_Click()

Dim test1Coll As Collection
Set test1Coll = testColl(Me, True)

MsgBox test1Coll(1).Name

End Sub

Private Sub CommandButton2_Click()

Dim test2Coll As Collection
Set test2Coll = testColl(Me, False)

MsgBox test2Coll(2).Name

End Sub

据我所知,只有当createColl为true时才创建集合,但是一旦创建了集合,它就像具有模块级作用域一样保留在内存中。

tktrz96b

tktrz96b3#

我会告诉你我通常是怎么做的。首先我使用字典而不是集合,更加灵活。字典在用户窗体级别作用域是公共的,所以它可以从工作簿中的任何地方访问。如果控件需要为事件编码,我会抛出一个类。
因为我不喜欢按名称调用窗体,所以我有一个函数,它在所有加载的userforms中循环,并在vba.userforms集合中给我它的索引。
最后,我的字典可以这样命名:第一个月
可以使用ifdict.exists()方法检查控件是否已经在其中,而不需要循环遍历整个现有字典。

相关问题