Excel VBA - .xlam(AddIn)抛出下标超出范围错误9但是一切都用作xlsm?

时间:2017-08-16 23:30:16

标签: excel vba excel-vba

锡上的标签基本上是什么。

我有多个用户表单,多个模块,类模块等。我有工作表,其中数据由代码存储和使用。我在功能区上添加了一个标签和按钮。

我运行并测试了从“Come Here”到“Sick'Em”的所有内容,作为.xlsm文件。每种形式,每个按钮,每行代码的每个字段都运行得很好。

我将文件保存为.xlam,并且在第一个模块中,这个代码就挂起了这个代码:

Worksheets("All Welders Data").Activate

正如我所说,我得到下标超出范围错误9。

这是我第一次尝试接受VBA项目并将其另存为加载项。我肯定错过了什么。我读过(John Walkenbach“Excell 2013 ...”).xlam文件仍然是带有工作表的工作簿,一切都应该像.xlsm一样工作。

是否错误表格是对工作表的引用?它是激活吗?我需要加前缀Something.Worksheets("blah").Activate吗?

我很累,而且我很难过。我希望有人对我有一些意见。提前谢谢!

更新

我想让所有人回答他们的回复和评论。我相信“ThisWorkbook”可能会解决这个问题。我现在很接近能够测试它,我将用我的结果再次更新我的问题。

但是,由于关于我使用激活的这篇文章有很多讨论,我想提出一个与所有这些相关的后续问题。

以下是我的某个模块的示例。

Private Sub UserForm_Initialize()
    Dim lastRow As Long
    Dim nameCell As Range
    Dim box As control

    'Set Window size and position
    With Application
        .WindowState = xlMaximized
        Me.Top = .Top * 0.5
        Me.Left = .Left * 1.0015
        Zoom = Int((.Width * 0.85) / (Width * 0.85) * 40)
        Width = .Width * 0.995
        Height = .Height * 0.992
    End With

    'Turn off everything except the radio Buttons and thier labels
    Me.submitButton.Visible = False
    Me.submitButton.Enabled = False
    Me.chooseWelderLabel.Visible = False
    Me.chooseWelderNameComboBox.Visible = False
    Me.chooseWelderNameComboBox.Enabled = False
    Me.welderNameLabel.Visible = False
    Me.welderNameText.Visible = False
    Me.welderNameText.Enabled = False
    Me.checkNameButton.Visible = False
    Me.checkNameButton.Enabled = False

    Application.ScreenUpdating = False

    'Activate the worksheet
    Application.ThisWorkbook.Worksheets("All Welders Data").Activate
    Application.ThisWorkbook.Worksheets("All Welders Data").Range("A1").Activate

    'sort the data in the active sheet by the welder's last name.

    With Application.ThisWorkbook.ActiveSheet.Sort
        .SortFields.Clear
        .SortFields.Add Key:=Range("B3"), Order:=xlAscending
        .SetRange ActiveCell.CurrentRegion.Offset(1)
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With

    Application.ScreenUpdating = True

    'populate the combox from the active sheet (welder name in the
    'first column, welder ID number in the second column.
    With Application.ThisWorkbook.ActiveSheet
        lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
        For Each nameCell In .Range("E3:E" & lastRow)
            If nameCell.Value <> "" Then
                With Me.chooseWelderNameComboBox
                    .ColumnCount = 2
                    .AddItem nameCell.Value
                    .List(.ListCount - 1, 1) = nameCell.Offset(, -1).Value
                    'ComboBox now shows the values in column "E" and the values
                    'in coulmn "D" - in that order, as in  "Name" - "ID Number".
                    '(the reverse order of the columns in the worksheet.)
                End With
            End If
        Next
    End With
End Sub

你会看到大约一半我激活了工作表。然后在下一行我激活一个范围。我需要激活范围,因为我随后在随后的With块中进行排序。排序已完成,因为ComboBox需要按字母顺序排列。

如果我要激活Range ("A1"),我必须确保工作表已激活。如果没有,那么Range("A1").Activate将失败并出现1004错误,因为除非单元所在的工作表是活动工作表,否则无法激活单元格。

因此,如果我将成为永远不会使用激活的核心,那么重构此代码的建议是什么,以便我可以使用excel的内置排序。我对做任何类型的循环例程不感兴趣。

最后的词

我只想感谢Robin MacKenzie的回答。她走在正确的轨道上并给出了解决问题的良好答案。

另外,我只是想说,我仍然认为有时使用激活并不是一种罪恶!

1 个答案:

答案 0 :(得分:1)

此MSDN上关于ThisWorkbook属性的评论:

  

使用此属性引用包含宏代码的工作簿。 ThisWorkbook是从加载项本身引用加载项工作簿的唯一方法。 ActiveWorkbook属性不会返回加载项工作簿;它返回调用加载项的工作簿.Workbooks属性可能会失败,因为在创建加载项时工作簿名称可能已更改。

(我的重点)

您应该这样做(并避免Activate):

Dim wsData As Worksheet

Set wsData = ThisWorkbook.Worksheets("All Welders Data") '<-- use ThisWorkbook

' no need to Activate - just use the data
Dim rngStuff As Range

Set rngStuff = wsData.Range("A1:G5") '<-- change hardcoded range to whatever you need
' now work with the range

修改

关于更新后的问题,我建议使用类似于下面的代码来填充ComboBox上的UserForm而不使用Activate。它除了处理加载ComboBox的部分之外进行了测试,主要是你的工作代码。

Option Explicit

Sub UserForm_Initialize()

    Dim wsData As Worksheet
    Dim rngToSortFirstCell As Range
    Dim lngLastRow As Long
    Dim rngNameCell As Range

    ' set a reference to the sheet
    Set wsData = ThisWorkbook.Worksheets("All Welders Data")

    ' clear existing sort fields
    wsData.Sort.SortFields.Clear

    ' set a reference to the header of range to sort
    Set rngToSortFirstCell = wsData.Range("B3")

    ' sort it by CurrentRegion of first cell
    rngToSortFirstCell.Sort Key1:=Range("B3").CurrentRegion, _
        Order1:=xlAscending, _
        Header:=xlYes, _
        MatchCase:=False, _
        SortMethod:=xlPinYin

    ' put welder names to combo box
    With wsData
        lngLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
        For Each rngNameCell In .Range("E3:E" & lngLastRow)
            If rngNameCell.Value <> "" Then
                With Me.chooseWelderNameComboBox
                    .ColumnCount = 2
                    .AddItem rngNameCell.Value
                    .List(.ListCount - 1, 1) = rngNameCell.Offset(, -1).Value
                    'ComboBox now shows the values in column "E" and the values
                    'in coulmn "D" - in that order, as in  "Name" - "ID Number".
                    '(the reverse order of the columns in the worksheet.)
                End With
            End If
        Next
    End With

End Sub