如何在VBA中设置和使用空范围?

8

我希望以以下方式使用空范围:

Set NewRange = Union(EmptyRange, SomeRange)

我尝试使用 NothingEmptyNullEmptyRange 设置为空范围,但出现“运行时错误 '5' 无效的过程调用或参数”错误,似乎我必须使用 If 语句或其他关键字来完成工作?

我可以使用:

If EmptyRange Is Nothing Then
   Set NewRange = SomeRange
Else
   Set NewRange = Union(EmptyRange, SomeRange)
End If

替代建设:

Set NewRange = Union(EmptyRange, SomeRange)
4个回答

3

当我需要将多个range对象组合在一起时,我使用这个函数来替代Application.Union,其中“零个或多个”范围可能为Nothing

Function union(ParamArray rgs() As Variant) As Range
  Dim i As Long
  For i = 0 To UBound(rgs())
    If Not rgs(i) Is Nothing Then
      If union Is Nothing Then Set union = rgs(i) Else Set union = Application.union(union, rgs(i))
    End If
  Next i
End Function

使用示例:

Sub demo_union()
  Dim rg1 As Range, rg2 As Range, rg3 As Range, newRg As Range
  Set rg1 = Range("A1")
  Set rg3 = Range("C3")
  Set newRg = union(rg1, rg2, rg3)
  newRg.Select
End Sub

以下是一种不会在返回的范围中重复重叠单元格的变体。

通常情况下,当使用Application.Union(或上述函数)组合重叠范围(例如,A1:B2B2:C3)时,结果将具有多个重叠单元格的副本。

例如,使用以下代码:
overlapping ranges A1:B2 and B2:C3

Application.Union([A1:B2], [B2:C3]).Cells.Count '8 cells (repeats B2)

↑...返回8个单元格:A1 B1 A2 B2 B2 C2 B3 C3
(并且For Each循环将有8次迭代。)

以下的union2函数解决了这个问题,它仅返回唯一的单元格,并处理空范围(而不会产生令人恼火的模糊错误信息"Invalid Procedure call or argument")。

Debug.Print union2([A1:B2], [B2:C3]).Cells.Count '7 cells

↑ ...返回7个单元格:A1 B1 A2 B2 C2 B3 C3
(For Each循环将进行7次迭代。)


0

您仍然可以使用将 Null 作为 EmptyRange 的 Application.Union。

Dim ActualRange As Range: Set ActualRange = ThisWorkbook.Sheets(1).Cells(1,1)
EmptyRange = Null
Result = Union(ActualRange, ActualRange, EmptyRange)

诀窍是将 ActualRange 传递两次(因为 Union 需要两个强制参数,并且不介意它们是否相同),并使用第三个可选参数来进行操作。如果您需要从零开始,可以执行以下操作:
MyRange = Null
For each Cell In SomeRange.Cells
    If ThisIsMyCell(Cell) Then MyRange = Union(Cell, Cell, MyRange)
Next

0

我使用了一个额外的变量来解决这个问题。我没有使用 If EmptyRange Is Nothing,而是如果我的计数器 j = 0,则 NewRange = SomeRange。以下是我的代码:

Public Sub copyLineData(line_array As Variant)
' Copys data from the line into the right sheet

Dim i As Integer
Dim j As Integer
Dim line As String
Dim rgn_data As Range
Dim rgn_selected As Range

Dim table_data As ListObject

Set rgn_data = getDynamicRangeFromSheet(Worksheets("Data"), "A1")
Set table_data = Sheets("Data").ListObjects.Add(xlSrcRange, rgn_data, xlListObjectHasHeaders:=xlYes)

' Get the selected rows
For i = 0 To ArrayLen(line_array) - 1
    line = line_array(i)
    ' Make selection
    table_data.Range.AutoFilter Field:=1, Criteria1:=line
    ' Copy data
    j = 0
    For Each Row In table_data.DataBodyRange.Rows
        If Row.EntireRow.Hidden = False Then
            If j = 0 Then
                Set rgn_selected = Row
            Else
                Set rgn_selected = Union(Row, rgn_selected)
            End If
             j = j + 1
        End If
    Next Row
    ' Copy selection
    rgn_selected.Copy Destination:=Sheets(line).Range("A1")
Next i
' Remove selection
table_data.Range.AutoFilter
' Convert back to range
table_data.Unlist
End Sub

-1

Union() 方法需要至少 2 个命名区域。它将这两个命名区域组合成一个主区域。如果你真正的目标是将 SomeRange 与一个 Empty 区域组合起来,那么你应该只需写:

Set NewRange = SomeRange

你使用 Union() 方法是无意义的,因为 Union() 需要两个已定义的范围。

http://msdn.microsoft.com/en-us/library/office/aa213609%28v=office.11%29.aspx


1
没有评论就点踩? - Chrismas007
9
我没有投反对票,但是你的回答说这个问题是无意义的,而实际上不是。例如,在循环中将单元格收集到一个范围内,您希望从空集开始,并在每次迭代中添加单元格。显然,您需要一个if语句来使其工作,这样不够优雅。 - TacoV

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接