【问题标题】:Why are public variables lost after an error?为什么公共变量在出错后会丢失?
【发布时间】:2018-02-05 10:48:00
【问题描述】:

我开发了以下两个子组件,它们创建和删除列表对象旁边的复选框集合。 listobject 中的每个不同 ID 都有一个复选框。像这样我可以批准 listobject 条目。

代码如下:

Public CBcollection As Collection
Public CTRLcollection As Collection

Sub create_chbx()
If Approval.CBcollection Is Nothing Then
Dim i As Integer
Dim tbl As ListObject
Dim CTRL As Excel.OLEObject
Dim CB As MSForms.CheckBox
Dim sht As Worksheet
Dim L As Double, T As Double, H As Double, W As Double
Dim rng As Range
Dim ID As Long, oldID As Long

Set CBcollection = New Collection
Set CTRLcollection = New Collection
Set sht = ActiveSheet
Set tbl = sht.ListObjects("ApprovalTBL")
Set rng = tbl.Range(2, 1).Offset(0, -1)
      W = 10
      H = 10
      L = rng.Left + rng.Width / 2 - W / 2
      T = rng.Top + rng.Height / 2 - H / 2

For i = 1 To tbl.ListRows.count
      ID = tbl.Range(i + 1, 1).Value
      If Not (ID = oldID) Then
            Set CTRL = sht.OLEObjects.Add(ClassType:="Forms.CheckBox.1", Link:=False, DisplayAsIcon:=False, Left:=L, Top:=T, Width:=W, Height:=H)
            Set CB = CTRL.Object
            CBcollection.Add Item:=CB
            CTRLcollection.Add Item:=CTRL
      End If

      Set rng = rng.Offset(1, 0)
      T = rng.Top + rng.Height / 2 - H / 2
      oldID = ID
Next i
End If
End Sub


Sub remove_chbx()
If Not Approval.CBcollection Is Nothing Then
With Approval.CBcollection ' Approval is the module name
      While .count > 0
            .Remove (.count)
      Wend
End With
With Approval.CTRLcollection
      While .count > 0
            .Item(.count).Delete
            .Remove (.count)
      Wend
End With
Set Approval.CBcollection = Nothing
Set Approval.CTRLcollection = Nothing
End If
End Sub

这一切都很好。如果没有复选框,则没有双复选框,也没有错误。如果我需要开发和测试其他模块,我正在开发一个批准计划。如果我现在运行这个子:

Sub IdoStupidStuff()
Dim i As Integer
Dim Im As Image

i = 1
Set Im = i
End Sub

它会给我一个错误。如果我然后尝试运行我的复选框潜艇之一,它们将不再正常工作。该集合被错误删除,我不再能够访问这些集合。为什么会发生这种情况,我是否能够采取其他措施而不是导致错误?如果收藏品丢失不是问题,是否有更好的方法来实施这样的系统?

【问题讨论】:

  • 这只是 VBA 工作方式的正常行为。如果您停止(而不是暂停)代码的执行(例如,因为豁免),那么所有变量都会被清除。如果您需要保存数据,则需要将其放入工作表中,如果您重新启动代码,您可以在初始化时阅读该工作表。此外,正确的错误处理将防止您的代码被终止。
  • 程序终止时所有变量都会丢失,一种方法是通过错误。阅读有关错误处理的信息。感兴趣的几个词是下一个简历等。
  • 您应该以这种方式更改您的 Vba 代码,它会在您每次运行代码时加载全局变量。不要期望 Vba 会在空闲时间保留全局变量,并且由于错误,它会在转到空闲时间时清除所有变量。
  • @Rolfi 和@peh:那会是什么样子?我将公共变量输入到工作表中初始化就是这样吗?
  • 是的,将所有持久值放入工作表中,并在每次运行代码之前读取它们。例如。您可以检查您的公共变量是否为空,如果是,请从工作表中读取,否则使用该变量。有很多方法取决于你如何实现它。

标签: vba excel checkbox collections


【解决方案1】:

您可以将 Collection 对象包装在一个 Property 中并让它处理对象的创建:

Private mCollection As Collection

Public Property Get TheCollection() As Collection
    If mCollection Is Nothing Then Set mCollection = New Collection
    Set TheCollection = mCollection
End Property

称呼它:

TheCollection.Count

【讨论】:

  • 很高兴知道!毕竟那些告诉我不可能最终解决的人。我已经考虑过只使用工作表的 OLEObjects 集合并手动确保只删除正确的对象。谢谢!
  • 尝试使用这种看起来很有趣的方法,我发现它只能通过模块访问。我已将其以加载事件的形式放入 MS Access VBA 代码中。但试图从任何其他模块调用它我得到“变量未定义”。真可惜,这真是一个好看的解决方案......
  • @Smok 表单的隐藏文件代码对于用于处理控制事件的表单是私有的,因此无法访问。如果你想要应用程序范围的访问,你必须把它放在一个标准模块中。然后可以使用ModuleName.TheCollection访问它。
  • 很棒的提示!甚至,似乎不需要使用模块名称!看起来使用 TheCollection 调用它就足够了。这对我来说已经足够了。你用我的配置模块为我节省了很多时间。
  • @Smok 确实没有必要,但可以帮助您找到属性/方法所在的模块。此外,如果您有 2 个具有相同名称的属性/方法(当然在不同的模块中),则需要模块名称来解决冲突。
【解决方案2】:

在导致错误的行之前尝试On Error Resume Next。它会跳过问题,您的变量仍然可用。 但是,这不会解决您的错误。尝试在您的工作簿中制作一个单独的隐藏表来存储您的全局变量,这样它们就不会丢失。 例:

Private Sub CreateSheet()
    Dim ws As Worksheet
    With ThisWorkbook
        Set ws = .Sheets.Add(After:=.Sheets(.Sheets.Count))
        ws.Name = "Global"
        .Worksheets("Global").Visible = False
    End With
End Sub

【讨论】:

    猜你喜欢
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    • 1970-01-01
    • 1970-01-01
    • 2014-11-26
    • 2020-12-19
    • 1970-01-01
    相关资源
    最近更新 更多