Excel VBA - 避免错误1004将UF ListBox数组写入工作表

时间:2017-09-16 16:25:02

标签: arrays excel-vba userform vba excel

任务

我的目的是使用数据字段方法以最有效的方式将UserForm列表框数据写回到工作表范围。

基本方法(尤其是使用数据范围)

AFAIK是将数据写入范围的最有效方法是使用数组。如果数据来自一个范围,那么它最好使用数据字段数组,默认情况下是二维(一个基于数组)并允许 a)从工作表到数组获取数据 b)将数组写回到表格 一个代码行:

Dim v   ' As Variant
Dim rng As Range
Set rng = ...

' a) range to array
      v = rng.Value

' b) array to range
     rng.Value = v

使用ListBox数据数组时的差异

ListBox数据存储在2dim中,但基于零的数组,例如的 ListBox1.List

[提示:因此,可以使用预定义的数组创建项目,而不是使用通常已知的Add方法,BTW仅限于10列(索引为0到9)。 ]

尽管存在这种差异,但可以读入ListBox数据并使用所描述的基本方法将它们写回工作表:

 ' aa) ListBox data to array
   v = Me.ListBox1.List

 ' bb) array to range
rng.Value = v

此外,我注意到默认情况下,数组列数为10,因此这不会对应于以编程方式设置的ColumnCount。因此,有必要调整检查阵列尺寸的范围,参见代码示例中的调试协议。

问题和解决方法

如果存在具有前导" =="的项目,则将数据字段数组写回到单个内容中的工作表会引发错误1004(应用程序定义的错误或对象定义的错误)。字符串或类似的用户输入,因为Excel无法正确解释。

我尝试使用

rng.Text  = v

而不是

rng.value = v

也失败了,导致424对象需要出错。

问题 ==>是否可以使用前导" ="来纠正潜在的错误项目?字符没有循环使用VBA或API方法通过所有数组项?欢迎任何代码示例替换我的工作(代码中的第3步)

我的代码

我的代码包含四个步骤 1)创建一个2dim数据字段数组(v) 2)设定目标范围(rng) 3)[我在纠正每个数组项目的工作] 4)将数据写回工作表

Private Sub CommandButton1_Click()
' declare variables
  Dim ws As Worksheet
  Set ws = ThisWorkbook.Worksheets("Dump")

  Dim s     As String             ' range address string
  Dim sTest As String             ' item test string
  Dim v     As Variant            ' data field array
  Dim rng   As Range              ' (target) range
  Dim i     As Long               ' rows counter
  Dim j     As Long               ' columns counter
  Dim R     As Long               ' number of rows
  Dim C     As Integer            ' number of columns
  Dim lbxR  As Long               ' actual number of listbox items   in data field
  Dim lbxC  As Integer            ' actual number of listbox columns in data field
' Error Handler
  On Error GoTo OOPS

' get programmatically defined listbox dimension
  R = Me.ListBox1.ListCount
  C = Me.ListBox1.ColumnCount
' clear sheet lines A2:A{r}
  ws.Range(ws.Cells(2, 1), ws.Cells(R, C)).value = ""
' ===============================
' 1) create 2dim data field array
' -------------------------------
  v = Me.ListBox1.List

' -------------------------------
' 2) set target range (rng)
' -------------------------------
' get actual data field dimension
  lbxR = UBound(v, 1) - LBound(v, 1) + 1    ' first dimension
  lbxC = UBound(v, 2) - LBound(v, 2) + 1    ' second dimension
  s = ws.Range("A2").Resize(lbxR, lbxC).Address
' set correconding target range
  Set rng = ws.Range(s)                           ' target range

' create short protocol - columns by default differ from user defined ColumnCount property !
  Debug.Print String(80, "-")
  Debug.Print vbNewLine & "** ListBox1 Defs            Data Field Array Dimension **"
  Debug.Print "                            [Target Range " & s & "]"
  Debug.Print String(80, "-")
  Debug.Print "   ListCount  = " & ListBox1.ListCount, "rows = " & lbxR & " = ubound(v,1)-lbound(v,1)+1 = " & UBound(v, 1) & " - " & LBound(v, 1) & " + 1 "
  Debug.Print "   ColumnCount= " & ListBox1.ColumnCount, "cols = " & lbxC & " = ubound(v,2)-lbound(v,2)+1 = " & UBound(v, 2) & " - " & LBound(v, 2) & " + 1 "
  Debug.Print String(80, "-")

' ----------------------------------------------------------------
' 3) Work around - correct leading "=", if any occurences presumed
'    (avoid error 1004 - App-defined or object-defined error)
' ----------------------------------------------------------------
' ==> Is there an alternative way? 
' For i = 0 To R - 1            ' edited thx to D.Lee 
'   For j = 0 To C - 1
'      v(i, j) = IIf(Left(Me.ListBox1.List(i, j) & "", 1) = "=", " ", "") & _
'                          Me.ListBox1.List(i, j)
'   Next j
' Next i     
' -------------------------------
' 4) write data back to worksheet
' -------------------------------
  rng.value = v

Exit Sub

' =============
' Error Handler
' =============
OOPS:
  MsgBox "ERL=" & Erl & " |Error " & Err.Number & "|" & Err.Description & vbNewLine & _
         "s=" & s, vbExclamation

End Sub  

提示我建议您阅读"Arrays and Ranges in VBA" by C.Pearson

自9月17日起对OP的补充(替代解决方案)

如果你知道第一个目标列是纯文本的,你可以在第[4]节之前编写以下语句,而不是搜索以=开头的每个列表项:

rng.Columns(1).NumberFormat = "@"

1 个答案:

答案 0 :(得分:1)

Lbound(v,1)= 0 ubound(v,1)= r-1 所以,它需要修改i和j。

  For i = 0 To R - 1
      For j = 0 To C - 1
         v(i, j) = IIf(Left(Me.ListBox1.List(i, j) & "", 1) = "=", " ", "") & _
                             Me.ListBox1.List(i, j)
      Next j
  Next i