自动过滤,然后xlcelltypevisible选择空行

时间:2014-04-29 01:11:53

标签: excel vba excel-vba autofilter

我是VBA和编程的新手。我正在使用excel中的大型数据表 - 我的工作表通常有65K行。

我想将两列作为输入,并将excel写入公式输出到两个新列。我不需要为所有行执行此操作,因此我尝试过滤我的数据并仅将计算输出应用于剩余的可见单元格。但是,我的代码似乎在底部添加了一堆额外的空白行(行计数气球到145K!),然后尝试计算这些行,这使得宏挂起。

如何解决此范围选择问题?另外,有更好的方法进行排序吗?谢谢!

Sub CalcSpec()
Dim s As Worksheet
For Each s In ActiveWorkbook.Sheets
        If (Left(s.Name, 7) = "Channel" And Right(s.Name, 1) = "1") Then
        s.Activate
        UserMassInput.Show 1 'Sets up value in R2C21 referenced later
        'Select only relevant data from cycles 1-5
        With ActiveSheet
        .AutoFilterMode = False
        .Range("A1:Q1").AutoFilter
        .Range("A1:Q1").AutoFilter Field:=6, Criteria1:="<=5"
        .Range("A1:Q1").AutoFilter Field:=5, Criteria1:=Array("2", "3", "5"), Operator:=xlFilterValues
        End With
        'Here's where I try and fail to select only the relevant range
        Dim cyCells As Range
        Set cyCells = Columns("R:S").SpecialCells(xlCellTypeVisible)
        'Apply formula to calculate specific capacities
        For Each cell In cyCells
            cell.FormulaR1C1 = "=RC[-9]*1000/R2C21"
        Next cell
        'Label all the new columns
        ActiveSheet.Range("R1").Value = "Spec CC"
        ActiveSheet.Range("S1").Value = "Spec DC"
        ActiveSheet.AutoFilterMode = False
    End If
Next s
End Sub

1 个答案:

答案 0 :(得分:2)

看起来您的代码看起来没有向表单添加任何内容,也许空行已经存在并且您只是因为操作而注意到它们?因为你正在做:

.Range("A1:Q1").AutoFilter

Excel将范围解释为该大小。有很多方法可以找到&#34;最后使用的行&#34;在工作表或范围中。试试这个方法:

http://www.siddharthrout.com/2012/10/02/find-last-row-in-an-excel-sheetvbavb-net/

确定上次使用的行后,更改自动过滤器范围以明确定义要过滤的范围。

尝试这样的事情。在我(最完整)较小的工作表上使用一些虚拟数据进行了相当全面的测试。

Option Explicit

Sub CalcSpec()
Dim s As Worksheet
Dim lRow As Long
Dim filteredRange As Range
Dim cl As Range
Dim a As Range
'## First, disable automatic calculation and screenupdating
Application.ScreenUpdating = False
Application.Calculation = -4135 'xlCalculationManual

For Each s In ActiveWorkbook.Sheets
    '## I modified this logic to use a GoTo instead of putting everything inside an If Block
    If Not ((Left(s.Name, 7) = "Channel" And Right(s.Name, 1) = "1")) Then GoTo NextSheet

    UserMassInput.Show 1 'Sets up value in R2C21 referenced later
    'Select only relevant data from cycles 1-5
    With s
    '## Define our range using the LAST_ROW of the worksheet
        Set filteredRange = .Range("A1:Q" & LastRow(s))
        .AutoFilterMode = False
    '## Apply autofilter Explicitly to the range defined above
        filteredRange.AutoFilter Field:=6, _
                                 Criteria1:="<=5"
        filteredRange.AutoFilter Field:=5, _
                                 Criteria1:=Array("2", "3", "5"), _
                                 Operator:=xlFilterValues

        'Here's where I try and fail to select only the relevant range
        Dim cyCells As Range
        Set cyCells = filteredRange.Resize(, 2).Offset(0, 17).SpecialCells(xlCellTypeVisible)
        'Apply formula to calculate specific capacities
    '## I'm pretty sure you need to iterate the AREAS in a filtered range,
    '   and then the cells/rows within each AREA
        For Each a In cyCells.Areas
            For Each cl In a.Cells
                cl.FormulaR1C1 = "=RC[-9]*1000/R2C21"
            Next
        Next

        'Label all the new columns
        .Range("R1").Value = "Spec CC"
        .Range("S1").Value = "Spec DC"
        .AutoFilterMode = False
    End With
NextSheet:
Next s


'## Remember to turn screenupdating and calculation back ON
Application.Calculation = -4105 'xlCalculationAutomatic
Application.ScreenUpdating = True

End Sub
Function LastRow(Optional ws As Worksheet = Nothing) As Long
If ws Is Nothing Then Set ws = ActiveSheet
Dim r As Long
r = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
LastRow = r
End Function

<强>更新

关于多个条件......我确实试图避免使用GoTo语句 - 它们会让人感到困惑,并且随着时间的推移难以维护代码。我在这种情况下使用它只是因为它真的出现了你只是想忽略不符合这些条件的纸张。

对于每个条件的多个条件和不同的操作,嵌套的If语句和/或使用Select Case语句通常是我喜欢的方式。你可以这样做:

For Each s In ActiveWorkbook.Sheets
    If Left(s.Name,7) = "Channel" Then
        Select Case Right(s.Name, 1) 
            Case "%" 
            ' 
            '
            ' Within this block you put your code
            ' to do opertations on sheets like Channel*%
            ' or, call an appropriate subroutine
            '
            Case "1"
            '
            ' Within this block you put your code
            ' do operations on sheets like Channel*1
            ' or, call an appropriate subroutine
            '
            '
            ' NOTE: You can add as many Case statements _
            '       as you need, BEFORE the "Case Else"
            Case Else
            ' do operations on other sheets, or ignore them

            '
            '
            '
        End Select
    End If
    If Left(s.Name, 10) = "Statistics" Then
        Select Case Right(s.Name, 1) 
            Case "%" 

            Case "1"

            Case Else

        End Select
    End If
Next