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

运行时创建的VBA TextBox无法引用,如何保存其数据?

问题修复与解决方案

先解决最根本的错误:控件创建参数顺序搞反了

你写的Controls.Add语句参数顺序错了,VBA里Forms.Controls.Add的正确语法是:

Controls.Add(控件类型ProgID, 控件名称, 是否可见)

你当前的代码是DocumentsForm.Controls.Add("Forms.Textbox.1", True),把「是否可见」的True传到了「控件名称」的位置,导致控件的Name根本不是你后续赋值的DocName & contCount,而是被设成了字符串"True"——这就是为什么遍历控件时名称为空、直接引用Type1会报「Object Required」的核心原因。

第一步:修正控件创建代码

把创建控件的语句改成这样,直接在创建时指定正确名称:

Set txtbox = DocumentsForm.Controls.Add("Forms.Textbox.1", DocName & contCount, True)

后续的.Name赋值可以保留也可以删掉,作为双重保障。

第二步:正确引用动态控件

动态创建的控件是后期绑定的,VBA编译时不认识Type1这种直接写的名称,必须通过窗体的Controls集合按名称访问:

' 给Type1文本框赋值
Me.Controls("Type1").Value = "Test"

' 读取Status2的内容
Dim statusContent As String
statusContent = Me.Controls("Status2").Value

第三步:批量保存用户输入

如果要把所有动态文本框的内容存起来(比如存到工作表),可以遍历控件集合,按命名规则筛选后写入:

Public Sub SaveAllInputs()
    Dim saveSheet As Worksheet
    Set saveSheet = ThisWorkbook.Sheets("数据存储") ' 替换为你的工作表名
    Dim currentRow As Integer
    currentRow = 2 ' 假设表头在第一行,从第二行开始存
    
    Dim ctrl As Control
    Dim lineNum As Integer
    Dim fieldName As String
    
    For Each ctrl In Me.Controls
        If TypeName(ctrl) = "TextBox" Then
            ' 从控件名拆分行号和字段名(比如Type1拆成字段Type、行号1)
            lineNum = Val(Right(ctrl.Name, Len(ctrl.Name) - InStrRev(ctrl.Name, "e"))) ' 根据你的命名规则调整提取逻辑
            fieldName = Left(ctrl.Name, InStr(ctrl.Name, CStr(lineNum)) - 1)
            
            ' 找到表头对应的列
            Dim targetCol As Integer
            targetCol = saveSheet.Rows(1).Find(fieldName, LookIn:=xlValues, LookAt:=xlWhole).Column
            
            ' 写入数据
            saveSheet.Cells(currentRow + lineNum - 1, targetCol).Value = ctrl.Value
        End If
    Next ctrl
End Sub

可选优化:用集合存动态控件(访问更高效)

如果要频繁操作这些动态控件,可以在创建时把它们放到一个集合里,后续直接从集合取,不用每次遍历控件:

' 在窗体模块顶部声明私有集合
Private dynamicTxtBoxes As Collection

' 修改AddLine_Click过程
Public Sub AddLine_Click()
    Static lineCount As Integer
    Dim txtbox As Object
    Dim docNames As Variant
    docNames = Array("Type", "Status", "Reference", "Units", "Quantity", "ValidityDate", "IssuingAuthority", "Reason")
    
    ' 第一次运行时初始化集合
    If dynamicTxtBoxes Is Nothing Then
        Set dynamicTxtBoxes = New Collection
    End If
    
    lineCount = lineCount + 1 ' 用静态变量直接计数,比遍历控件高效
    Dim prevWidth As Single
    prevWidth = 0
    
    For Each docName In docNames
        Set txtbox = DocumentsForm.Controls.Add("Forms.Textbox.1", docName & lineCount, True)
        Dim templateWidth As Single
        templateWidth = DocumentsForm.Controls("Doc" & docName).Width
        
        With txtbox
            .Left = 10.5 + prevWidth
            .Height = 26.25
            .Top = 47.25 + (26.25 * lineCount)
            .Width = templateWidth
            .SpecialEffect = fmSpecialEffectFlat
            .BorderStyle = fmBorderStyleSingle
            .BorderColor = &H80000000
        End With
        
        ' 把控件加到集合,用名称当键
        dynamicTxtBoxes.Add txtbox, docName & lineCount
        prevWidth = prevWidth + templateWidth
    Next
End Sub

' 示例:从集合取控件操作
Public Sub UpdateType1()
    Dim typeBox As Object
    Set typeBox = dynamicTxtBoxes("Type1")
    typeBox.Value = "测试内容"
    
    ' 遍历集合打印所有内容
    Dim item As Object
    For Each item In dynamicTxtBoxes
        Debug.Print item.Name & ": " & item.Value
    Next
End Sub

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:07:59