【问题标题】:Easiest way to loop through a filtered list with VBA?使用 VBA 遍历过滤列表的最简单方法是什么?
【发布时间】:2012-06-06 15:06:51
【问题描述】:

如果我在 Excel 中设置了一个自动过滤器,并且我想使用 VBA 代码遍历一列中的所有可见数据,那么最简单的方法是什么?

不应包含所有已过滤掉的隐藏行,因此从上到下的普通 Range 无济于事。

有什么好主意吗?

【问题讨论】:

    标签: excel vba


    【解决方案1】:

    假设我的单元格 A2:A11 中有数字 1 到 10,而我的自动过滤器在 A1 中。我现在过滤以仅显示大于 5 的数字(即 6、7、8、9、10)。

    此代码将只打印可见单元格:

    Sub SpecialLoop()
        Dim cl As Range, rng As Range
        
        Set rng = Range("A2:A11")
        
        For Each cl In rng
            If cl.EntireRow.Hidden = False Then //Use Hidden property to check if filtered or not
                Debug.Print cl
            End If
        Next
    
    End Sub
    

    也许SpecialCells 有更好的方法,但以上方法在 Excel 2003 中对我有用。

    编辑

    刚刚找到SpecialCells 的更好方法:

    Sub SpecialLoop()
        Dim cl As Range, rng As Range
        
        Set rng = Range("A2:A11")
        
        For Each cl In rng.SpecialCells(xlCellTypeVisible)
            Debug.Print cl
        Next cl
    
    End Sub
    

    【讨论】:

    • 感谢您的所有回答!它们或多或少都相同(使用 SpecialCells(xlCellTypeVisible) 是我需要的关键)所以很难选择哪个答案是正确的。
    • 使用Debug.Print cl.row获取行号或cl.address
    • 注意如果您在该范围内有隐藏列,则SpecialCells(xlCellTypeVisible) 返回的数据可能从第一列开始,或者从隐藏列之后的列开始。
    【解决方案2】:

    我建议使用 Offset 假设标题位于第 1 行。请参阅此示例

    Option Explicit
    
    Sub Sample()
        Dim rRange As Range, filRange As Range, Rng as Range
        'Remove any filters
        ActiveSheet.AutoFilterMode = False
    
        '~~> Set your range
        Set rRange = Sheets("Sheet1").Range("A1:E10")
    
        With rRange
            '~~> Set your criteria and filter
            .AutoFilter Field:=1, Criteria1:="=1"
    
            '~~> Filter, offset(to exclude headers)
            Set filRange = .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow
    
            Debug.Print filRange.Address
    
            For Each Rng In filRange
                '~~> Your Code
            Next
        End With
    
        'Remove any filters
        ActiveSheet.AutoFilterMode = False
    End Sub
    

    【讨论】:

    • 这是解决问题的好方法。我喜欢你的方法。
    • 很好的解决方案 Sid。但是,我在使用SpecialCells 时会非常小心。我最近遇到了一个问题,因为 Excel 发送这些单元格的 .Address 的方式(基于它们的连续出现)。
    • @PankajJaju:对不起,我没有得到你。你能解释一下你是什么意思吗?也许有一个例子?
    • @SiddharthRout - 如果您遍历特殊单元格的地址(让我们在 A 列上说),那么它将为您提供类似 $A1、$A3:$A5、$A7、$A10 的地址: $A15 等等。请注意,如果可见行是连续的,它们将显示为连续范围,如 $A10:$A15 否则它们将是单独的单元格,如 $A1、$A7 等。
    • 我在 Set filRange = .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow 上遇到“运行时错误 1004:应用程序定义或对象定义错误”。上面代码的唯一区别是我的范围是 .Range("A:J")
    【解决方案3】:

    一种方式假设A1中的过滤数据向下;

    dim Rng as Range
    set Rng = Range("A2", Range("A2").End(xlDown)).Cells.SpecialCells(xlCellTypeVisible)
    ...
    for each cell in Rng 
       ...     
    

    【讨论】:

      【解决方案4】:

      我使用了范围的RowHeight 属性(也表示单元格)。如果它为零,则它是隐藏的。 因此,只需像往常一样遍历所有行,但是在 if 条件中检查该属性,就像在 If myRange.RowHeight > 0 then DoStuff 中一样,其中 DoStuff 是您想要对可见单元格执行的操作。

      【讨论】:

        【解决方案5】:

        SpecialCells 实际上并不工作,因为它需要是连续的。我通过添加排序功能解决了这个问题,以便根据我需要的列对数据进行排序。

        抱歉,代码中没有 cmets,因为我不打算分享它:

        Sub testtt()
            arr = FilterAndGetData(Worksheets("Data").range("A:K"), Array(1, 9), Array("george", "WeeklyCash"), Array(1, 2, 3, 10, 11), 1)
            Debug.Print sms(arr)
        End Sub
        Function FilterAndGetData(ByVal rng As Variant, ByVal fields As Variant, ByVal criterias As Variant, ByVal colstoreturn As Variant, ByVal headers As Boolean) As Variant
        Dim SUset, EAset, CMset
        If Application.ScreenUpdating Then Application.ScreenUpdating = False: SUset = False Else SUset = True
        If Application.EnableEvents Then Application.EnableEvents = False: EAset = False Else EAset = True
        If Application.Calculation = xlCalculationAutomatic Then Application.Calculation = xlCalculationManual: CMset = False Else CMset = True
        For Each col In rng.Columns: col.Hidden = False: Next col
        
        Dim oldsheet, scol, ecol, srow, hyesno As String
        Dim i, counter As Integer
        
        oldsheet = ActiveSheet.Name
        
        
        Worksheets(rng.Worksheet.Name).Activate
        
        Worksheets(rng.Worksheet.Name).AutoFilterMode = False
        
        scol = Chr(rng.Column + 64)
        ecol = Chr(rng.Columns.Count + rng.Column + 64 - 1)
        srow = rng.row
        
        If UBound(fields) - LBound(fields) <> UBound(criterias) - LBound(criterias) Then FilterAndGetData = "Fields&Crit. counts dont match": GoTo done
        
        dd = sortrange(rng, colstoreturn, headers)
        
        For i = LBound(fields) To UBound(fields)
            rng.AutoFilter Field:=CStr(fields(i)), Criteria1:=CStr(criterias(i))
        Next i
        
        Dim rngg As Variant
        
        rngg = rng.SpecialCells(xlCellTypeVisible)
        Debug.Print ActiveSheet.AutoFilter.range.address
        FilterAndGetData = ActiveSheet.AutoFilter.range.SpecialCells(xlCellTypeVisible).Value
        
        For Each row In rng.Rows
            If row.EntireRow.Hidden Then Debug.Print yes
        Next row
        
        
        done:
            'Worksheets("Data").AutoFilterMode = False
            Worksheets(oldsheet).Activate
            If SUset Then Application.ScreenUpdating = True
            If EAset Then Application.EnableEvents = True
            If CMset Then Application.Calculation = xlCalculationAutomatic
        End Function
        Function sortrange(ByVal rng As Variant, ByVal colnumbers As Variant, ByVal headers As Boolean)
        
            Dim SUset, EAset, CMset
            If Application.ScreenUpdating Then Application.ScreenUpdating = False: SUset = False Else SUset = True
            If Application.EnableEvents Then Application.EnableEvents = False: EAset = False Else EAset = True
            If Application.Calculation = xlCalculationAutomatic Then Application.Calculation = xlCalculationManual: CMset = False Else CMset = True
            For Each col In rng.Columns: col.Hidden = False: Next col
        
            Dim oldsheet, scol, srow, sortcol, hyesno As String
            Dim i, counter As Integer
            oldsheet = ActiveSheet.Name
            Worksheets(rng.Worksheet.Name).Activate
            Worksheets(rng.Worksheet.Name).AutoFilterMode = False
            scol = rng.Column
            srow = rng.row
        
            If headers Then hyesno = xlYes Else hyesno = xlNo
        
            For i = LBound(colnumbers) To UBound(colnumbers)
                rng.Sort key1:=range(Chr(scol + colnumbers(i) + 63) + CStr(srow)), order1:=xlAscending, Header:=hyesno
            Next i
            sortrange = "123"
        done:
            Worksheets(oldsheet).Activate
            If SUset Then Application.ScreenUpdating = True
            If EAset Then Application.EnableEvents = True
            If CMset Then Application.Calculation = xlCalculationAutomatic
        End Function
        

        【讨论】:

          【解决方案6】:
          a = 2
          x = 0
          
          Do Until Cells(a, 1).Value = ""
          If Rows(a).Hidden = False Then
          x = Cells(a, 1).Value + x
          End If
          a = a + 1
          Loop
          
          End Sub
          

          【讨论】:

          • 虽然此代码可能会解决问题,但 including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的答案添加解释,并说明适用的限制和假设。
          【解决方案7】:
          Thisworkbook.sheets("Mysheet").Range("A1).Currentregion.copy 
          Thisworkbook.sheets("Othersheet").Range("A1)
          

          【讨论】:

          【解决方案8】:
          Call MyMacro()
          
          ActiveCell.Offset(1, 0).Activate
          
          Do Until Selection.EntireRow.Hidden = False
          If Selection.EntireRow.Hidden = True Then
          ActiveCell.Offset(1, 0).Activate
          End If
          Loop
          

          【讨论】:

          • 如果您提供一些解释代码的作用会很有帮助。
          猜你喜欢
          • 1970-01-01
          • 2011-04-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-21
          相关资源
          最近更新 更多