You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VBA UserForm点击New按钮打开窗体时出现“Subscript out of range”错误

VBA UserForm点击New按钮触发"Subscript out of range"错误的解决方案

我是VBA新手,正在创建一个UserForm,用户可通过ListBox查看表格信息。窗体设有New、Edit、Delete和Close按钮,点击New按钮时返回“Subscript out of range”错误,调试指向buttonNovo_Click事件中的frm.Show语句。尝试过修改窗体名称、直接调用formNovo.Show等方法,均未解决问题,以下是完整代码及代码结构截图:

代码结构截图

代码结构

完整代码

modMain

Option Explicit

Public Sub Main()

    Dim frm As New formRegistro
    frm.Show
    Set frm = Nothing
    
End Sub

modRange

Option Explicit

Public ws As Worksheet

Public Function GetRange() As Range
    Set ws = ActiveWorkbook.Worksheets("Registro")
    Set GetRange = ws.Range("A1").CurrentRegion
    Set GetRange = GetRange.Offset(1).Resize(GetRange.Rows.Count - 1)
End Function

Public Sub deleterow(ByVal row As Long)
    Set ws = ActiveWorkbook.Worksheets("Registro")
    ws.Range("A2").Offset(row).EntireRow.Delete
End Sub

Public Function GetNewID() As Long
    GetNewID = 1 + WorksheetFunction.Max(ws.Range("A2").CurrentRegion.Columns(1))
End Function

Public Function GetTurno() As Variant
    Dim wo As Worksheet
    Set wo = ActiveWorkbook.Worksheets("Oculto")
    GetTurno = ws.ListObjects("tbTurno").DataBodyRange.Value
End Function

formRegistro

Option Explicit

Private Sub buttonClose_Click()
    Unload Me
End Sub

Private Sub buttonNovo_Click()
    Dim frm As New formNovo
    frm.Show
End Sub

Private Sub buttonEdit_Click()
    Dim frm As New formAtt
    frm.Show
End Sub

Private Sub buttonDelete_Click()
    Call deleterow(listRegistro.ListIndex)
End Sub

Private Sub UserForm_Initialize()
    Call AddDataToListBox
End Sub

Public Sub AddDataToListBox()
    Dim rg As Range
    Set rg = GetRange()
    
    With listRegistro
        .RowSource = rg.Address(external:=True)
        .ColumnCount = rg.Columns.Count
        .ColumnWidths = "65,2 pt;97,8 pt;97,8 pt;130,4 pt;130,4 pt;65,2 pt;163 pt"
        .ColumnHeads = True
        .ListIndex = 0
    End With
End Sub

formNovo

Option Explicit

Private Sub buttonFechar_Click()
    Unload Me
End Sub

Private Sub buttonSalvar_Click()
    
    If MsgBox("Deseja salvar dados?", vbYesNo, "Save Record") = vbYes Then
        'Escrever dados dos controles ao banco de dados
        Call WriteDataToSheet
    
        'Limpar as caixas de texto
        Call EmptyTextBoxes
    
        'Criar um novo ID
        Call CreateID
        
    End If
    
End Sub

Private Sub WriteDataToSheet()

    Set ws = ActiveWorkbook.Worksheets("Registro")
    Dim newRow As Integer
    
    With ws
        newRow = .Cells(.Rows.Count, 1).End(xlUp).Rows + 1
        newRow = newRow + 1
        .Cells(newRow, 1).Value = txtID.Value
        .Cells(newRow, 2).Value = txtData.Value
        .Cells(newRow, 3).Value = txtHora.Value
        .Cells(newRow, 4).Value = txtCarga.Value
        .Cells(newRow, 5).Value = txtPlaca.Value
        .Cells(newRow, 6).Value = comboboxTurno.Value
        .Cells(newRow, 7).Value = txtRespons.Value
    End With
End Sub

Private Sub EmptyTextBoxes()
    Dim c As Control
    For Each c In Me.Controls
        If TypeName(c) = "TextBox" Then
            c.Value = ""
        End If
    Next c
End Sub


Private Sub UserForm_Initialize()

    'criar ID
    Call CreateID
    'iniciar controle
    Call InitializeControls
    
End Sub

Private Sub CreateID()
    Me.txtID.Value = GetNewID()
End Sub

Private Sub InitializeControls()
    Me.comboboxTurno.List = GetTurno()
    Me.comboboxTurno.ListIndex = 0
    
End Sub

错误原因及修复方案

1. 核心错误:GetTurno函数对象引用错误

modRange中的GetTurno函数里,你定义了wo指向"Oculto"工作表,但实际调用ListObject时错误使用了全局变量ws(指向"Registro"工作表),导致找不到名为tbTurno的ListObject,触发下标越界错误。

修复代码:

Public Function GetTurno() As Variant
    Dim wo As Worksheet
    Set wo = ActiveWorkbook.Worksheets("Oculto")
    GetTurno = wo.ListObjects("tbTurno").DataBodyRange.Value
End Function

2. GetNewID函数依赖全局变量风险

GetNewID使用全局ws变量,若ws未初始化(比如首次打开formNovo时未调用过GetRange),会导致访问Range出错。同时需处理空表场景,避免Max函数报错。

修复代码:

Public Function GetNewID() As Long
    Dim ws As Worksheet
    Set ws = ActiveWorkbook.Worksheets("Registro")
    ' 处理空表,避免Max函数报错
    If ws.Range("A2").Value = "" Then
        GetNewID = 1
    Else
        GetNewID = 1 + WorksheetFunction.Max(ws.Range("A2").CurrentRegion.Columns(1))
    End If
End Function

3. WriteDataToSheet中行号计算错误

原代码中newRow = .Cells(.Rows.Count, 1).End(xlUp).Rows + 1是错误的(应该用.Row而非.Rows),且重复加1会导致空行。

修复代码:

Private Sub WriteDataToSheet()
    Dim ws As Worksheet
    Set ws = ActiveWorkbook.Worksheets("Registro")
    Dim newRow As Long
    
    With ws
        newRow = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
        .Cells(newRow, 1).Value = txtID.Value
        .Cells(newRow, 2).Value = txtData.Value
        .Cells(newRow, 3).Value = txtHora.Value
        .Cells(newRow, 4).Value = txtCarga.Value
        .Cells(newRow, 5).Value = txtPlaca.Value
        .Cells(newRow, 6).Value = comboboxTurno.Value
        .Cells(newRow, 7).Value = txtRespons.Value
    End With
End Sub

4. 优化建议

尽量避免使用全局变量(如Public ws As Worksheet),在每个需要的过程中局部声明并初始化工作表对象,减少因变量状态异常导致的错误。


内容的提问来源于stack exchange,提问作者Lucas Kanda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 19:05:35