【问题标题】:Getting the actual usedrange获取实际使用范围
【发布时间】:2011-09-14 21:09:29
【问题描述】:

我有一个带有按钮的 Excel 工作表。

当我调用 usedRange() 函数时,它返回的范围包括按钮部分。

反正我可以得到包含数据的实际使用范围吗?

【问题讨论】:

    标签: excel vba


    【解决方案1】:

    什么样的按钮,窗体控件和 ActiveX 控件都不应该影响使用的范围。

    excel 不能很好地跟踪使用的范围是一个已知问题。通过 VBA 对使用范围的任何引用都会将该值重置为当前使用的范围。所以尝试运行这个子过程:

    Sub ResetUsedRng()
        Application.ActiveSheet.UsedRange 
    End Sub 
    

    如果你可能有一些格式悬而​​未决。尝试清除/删除最后一行之后的所有单元格。

    关于以上内容另见:

    Excel Developer Tip

    另一种查找最后使用的单元格的方法:

        Dim rLastCell As Range
    
        Set rLastCell = ActiveSheet.Cells.Find(What:="*", After:=.Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
        xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False)
    

    更改搜索方向以查找第一个使用的单元格。

    【讨论】:

    • 我会试试这个。我最终编写了自己的搜索功能。基本上,如果我找到一个空单元格,我会计算下一个 100 行。如果总数为 0,我认为它是最后一行。
    • 在调用Find之前,请确保您有ActiveSheet.AutoFilterMode=False,否则将不会考虑某些具有实际内容的行。
    • 没有。 Sheet.UsedRange 不能可靠地重置它。它有时会出错并一直出错。 Excel 2007 似乎确实有所改善。
    • ...但仍然可能出错,特别是如果有数据透视表。
    • 至少在 Excel 2016 中,.Find 命令在用于 .Cells 范围时会跳过合并的单元格,不幸的是,当它们位于已用范围的边界时。
    【解决方案2】:

    Readify 给出了非常完整的答案。但是,我想添加End 语句,您可以使用:

    在列中的空白之前查找最后使用的单元格:

    Sub LastCellBeforeBlankInColumn()
    Range("A1").End(xldown).Select
    End Sub
    

    在列中查找最后使用的单元格:

    Sub LastCellInColumn()
    Range("A" & Rows.Count).End(xlup).Select
    End Sub
    

    查找行中空白之前的最后一个单元格:

    Sub LastCellBeforeBlankInRow()
    Range("A1").End(xlToRight).Select
    End Sub
    

    查找一行中最后使用的单元格:

    Sub LastCellInRow()
    Range("IV1").End(xlToLeft).Select
    End Sub
    

    请参阅here 了解更多信息(以及为什么xlCellTypeLastCell 不太可靠的解释)。

    【讨论】:

    • +1 很棒的信息。我建议使用 Range("A" & Rows.Count).End(xlup) 这样您的代码对于多个版本的 excel 都是可行的。
    【解决方案3】:

    根据上述 Reafidy 的解决方案,这是一对返回工作表的最后一行和最后一行的函数。

        Function LastRow(ws As Object) As Long
    
            Dim rLastCell As Object
            On Error GoTo ErrHan
            Set rLastCell = ws.Cells.Find("*", ws.Cells(1, 1), , , xlByRows, _
                                          xlPrevious)
            LastRow = rLastCell.Row
    
        ErrExit:
            Exit Function
    
        ErrHan:
            MsgBox "Error " & Err.Number & ": " & Err.Description, _
                   vbExclamation, "LastRow()"
            Resume ErrExit
    
        End Function
    
        Function LastCol(ws As Object) As Long
    
            Dim rLastCell As Object
            On Error GoTo ErrHan
            Set rLastCell = ws.Cells.Find("*", ws.Cells(1, 1), , , xlByColumns, _
                                          xlPrevious)
            LastCol = rLastCell.Column
    
        ErrExit:
            Exit Function
    
        ErrHan:
            MsgBox "Error " & Err.Number & ": " & Err.Description, _
                   vbExclamation, "LastRow()"
            Resume ErrExit
    
        End Function
    

    【讨论】:

    • 非常好。我使用了二进制搜索,但这更简单,应该更快。但是,您可能还想指定 Lookin:=xlFormulas;公式可能会返回 ""
    • 其实不是,""匹配"*",和isempty()不同。
    【解决方案4】:
    Public Sub FindTrueUsedRange(RowLast As Long, ColLast As Long)
        Application.EnableEvents = False
        Application.ScreenUpdating = False
        RowLast = 0
        ColLast = 0
        ActiveSheet.UsedRange.Select
        Cells(1, 1).Activate
        Selection.End(xlDown).Select
        Selection.End(xlDown).Select
        On Error GoTo -1: On Error GoTo Quit
        Cells.Find(What:="*", LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Activate
        On Error GoTo -1: On Error GoTo 0
        RowLast = Selection.Row
        Cells(1, 1).Activate
        Selection.End(xlToRight).Select
        Selection.End(xlToRight).Select
        Cells.Find(What:="*", LookIn:=xlFormulas, LookAt:=xlWhole, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Activate
        ColLast = Selection.Column
    Quit:
        Application.ScreenUpdating = True
        Application.EnableEvents = True
        On Error GoTo -1: On Error GoTo 0
    End Sub
    

    【讨论】:

      【解决方案5】:

      此函数将实际使用的范围返回到右下限。如果工作表为空,则返回“Nothing”。

      '2020-01-26
      Function fUsedRange() As Range
      Dim lngLastRow As Long
      Dim lngLastCol As Long
      Dim rngLastCell As Range
          On Error Resume Next
          Set rngLastCell = ActiveSheet.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious)
          If rngLastCell Is Nothing Then  'look for data backwards in rows
              Set fUsedRange = Nothing
              Exit Function
          Else
              lngLastRow = rngLastCell.Row
          End If
          Set rngLastCell = ActiveSheet.Cells.Find("*", searchorder:=xlByColumns, searchdirection:=xlPrevious)
          If rngLastCell Is Nothing Then  'look for data backwards in columns
              Set fUsedRange = Nothing
              Exit Function
          Else
              lngLastCol = rngLastCell.Column
          End If
          Set fUsedRange = ActiveSheet.Range(Cells(1, 1), Cells(lngLastRow, lngLastCol))  'set up range
      End Function
      

      【讨论】:

        【解决方案6】:

        我使用以下 vba 代码来确定工作表的整个使用行范围,然后缩短列的选定范围:

            Set rUsedRowRange = Selection.Worksheet.UsedRange.Columns( _
            Selection.Column - Selection.Worksheet.UsedRange.Column + 1)
        

        反之亦然:

            Set rUsedColumnRange = Selection.Worksheet.UsedRange.Rows( _
            Selection.Row - Selection.Worksheet.UsedRange.Row + 1)
        

        【讨论】:

          【解决方案7】:

          这个函数给出了使用范围的所有 4 个限制:

          Function FindUsedRangeLimits()
              Set Sheet = ActiveSheet
              Sheet.UsedRange.Select
          
              ' Display the range's rows and columns.
              row_min = Sheet.UsedRange.Row
              row_max = row_min + Sheet.UsedRange.Rows.Count - 1
              col_min = Sheet.UsedRange.Column
              col_max = col_min + Sheet.UsedRange.Columns.Count - 1
          
              MsgBox "Rows " & row_min & " - " & row_max & vbCrLf & _
                     "Columns: " & col_min & " - " & col_max
              LastCellBeforeBlankInColumn = True
          End Function
          

          【讨论】:

          • UsedRange 的定义还包括格式化的单元格,即使它们是空的。大多数时候,我需要将 UsedRange 定义为非空单元格。
          【解决方案8】:

          在 Excel 2013 上的时间相当慢,使用范围非常大,百万行:

          26ms Cells.Find xlPrevious 方法(同上)

          0.4ms Sheet.UsedRange(随便叫)

          0.14ms Counta 二分搜索 + 0.4ms Used Range 开始搜索(12 CountA 调用)

          因此,如果担心的话,Find xlPrevious 会很慢。

          CountA 二分查找方法是先做一个Used Range。然后将范围切成两半,看看下半部分是否有非空单元格,然后根据需要再次减半。做对是很棘手的。

          【讨论】:

            【解决方案9】:

            这是另一个。它查找第一个和最后一个非空单元格,并且构建范围来自这些单元格。这也可以处理您的数据不是矩形且不是从 A1 开始的情况。此外,它还处理合并的单元格,当从宏执行时,.Find 会跳过这些单元格,用于工作表上的 .Cells。

            Function getUsedRange(ByRef sheet As Worksheet) As Range
            ' finds used range by looking for non empty cells
            ' works around bug in .Find that skips merged cells
            ' by starting at with the UsedRange (that may be too big)
            
            ' credit to https://contexturesblog.com/archives/2012/03/01/select-actual-used-range-in-excel-sheet/
            ' for the .Find commands
            
            Dim excelsUsedRange As Range
            Dim lastRow As Long
            Dim lastCol As Long
            Dim lastCell As Range
            Dim firstRow As Long
            Dim firstCol As Long
            Dim firstCell As Range
            
            Set excelsUsedRange = ActiveSheet.UsedRange
            
            lastRow = excelsUsedRange.Find(What:="*", _
                                           LookIn:=xlValues, SearchOrder:=xlRows, _
                                           SearchDirection:=xlPrevious).Row
            lastCol = excelsUsedRange.Find(What:="*", _
                                           LookIn:=xlValues, SearchOrder:=xlByColumns, _
                                           SearchDirection:=xlPrevious).Column
            Set lastCell = sheet.Cells(lastRow, lastCol)
            
            firstRow = excelsUsedRange.Find(What:="*", After:=lastCell, _
                                            LookIn:=xlValues, SearchOrder:=xlRows, _
                                            SearchDirection:=xlNext).Row
            firstCol = excelsUsedRange.Find(What:="*", After:=lastCell, _
                                            LookIn:=xlValues, SearchOrder:=xlByColumns, _
                                            SearchDirection:=xlNext).Row
            Set firstCell = sheet.Cells(firstRow, firstCol)
            Set getUsedRange = sheet.Range(firstCell, lastCell)
            End Function
            

            【讨论】:

              猜你喜欢
              • 2021-07-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-03-09
              • 2017-01-17
              • 1970-01-01
              • 2018-08-30
              • 1970-01-01
              相关资源
              最近更新 更多