2017-08-31 141 views
0

我试图写一个代码,它将查看从第4行到R2000的B2中的单元格,如果内容为零,则隐藏该行。我的问题是,代码运行速度非常慢,并经常停止响应。 如果你能帮助我,它导致它运行缓慢,我可以自己修复它,但我不确定什么是更有效的方法。正如你所看到的,我尝试过关闭屏幕更新,但没有多大帮助。缓慢的Excel VBA代码

的代码如下

Sub HideRows() 

    BeginRow = 4 
    EndRow = 2059 
    ChkCol = 2 

    Application.ScreenUpdating = False 

    Rows("1:2059").EntireRow.Hidden = False 


    For RowCnt = BeginRow To EndRow 
     If Cells(RowCnt, ChkCol).Value = 0 Then 
      Cells(RowCnt, ChkCol).EntireRow.Hidden = True 
     End If 
    Next RowCnt 

    Application.ScreenUpdating = True 

End Sub 
+0

这是否加快速度? '行(RowCnt).Hidden = True' – jsotola

+0

我刚刚试过你的代码。它花了不到1/2秒。在空白工作表上的新工作簿中进行试用。 – jsotola

+0

我敢打赌你的工作表在每次改变时都会进行计算。关闭类似'Application.EnableEvents = False'的事件,然后在重新启用屏幕更新时重新打开它们。 – Tim

回答

0

您可以使用自动过滤器吗?


Option Explicit 

Public Sub HideRowsWhereColBis0() 

    ActiveSheet.Range("B4:B2059").AutoFilter Field:=1, Criteria1:="<>0" 

End Sub 

+0

这是一个很棒的解决方案 - 没想到它。完美的作品:) –

1

试着隐藏一切都在一个去,而不是每一个0被发现

Sub HideRows() 
    Dim BeginRow As Long, EndRow As Long, ChkCol As Long 
    Dim HideRng As Range 

    BeginRow = 4 
    EndRow = 2059 
    ChkCol = 2 

    Application.ScreenUpdating = False 

    Rows("1:2059").EntireRow.Hidden = False 

    For rowcnt = BeginRow To EndRow 
     If Cells(rowcnt, ChkCol).Value2 = 0 Then 
      If HideRng Is Nothing Then 
       Set HideRng = Cells(rowcnt, ChkCol) 
      Else 
       HideRng = Union(HideRng, Cells(rowcnt, ChkCol)) 
      End If 
     End If 
    Next rowcnt 

    If Not HideRng Is Nothing Then HideRng.EntireRow.Hidden = True 

    Application.ScreenUpdating = True 

End Sub 
+0

唯一的缺点是它使用“联盟”,这在OP的情况下很好(只处理几千行),但在需要隐藏数十或数十万行时变得非常缓慢。 –

+0

是吗?不知道 - 很高兴知道。你知道原因吗? – Tom

+0

是的,当我最初从我的答案中创建“hideRows”宏时,我遇到了这个问题。不完全确定它为什么会发生,但随着您添加更多范围,Union会逐渐变慢(https://stackoverflow.com/questions/29230757/how-to-make-union-range-faster-for-large-loops) 。该解决方法涉及到将需要隐藏的行的字符串表示连接起来(例如“1:1,3:7,10:30”),并使用“Worksheet.Range(toHide)”来创建一个变量(在我的代码中为“toHide”)。 “来隐藏它们。你必须用255个字符的块来做,因为某些原因它不会接受更大的字符串。烦人复杂! –

1

没有看到您的工作簿时,很难知道肯定,但一般Excel在隐藏行时非常缓慢。在您的代码中,每行都隐藏一行,因此可能有超过1000个单独的“隐藏此行”命令到Excel。

隐藏“块”中的行要快得多。这个宏(我在很久以前就写过,因为我正在处理同样的问题)这样做,所以它应该快得多。在你的情况,你会这样称呼它:

Call hideRows(ActiveSheet, 4, 2059, 0, 2, 2) 

还有会隐藏行除非在第2列的值等于零倒置的设置。你只需要在你的函数调用结尾添加“True”。

Sub hideRows(ws As Worksheet, startRow As Long, endRow As Long, valCrit As Variant, Optional startCol As Long = 1, Optional endCol As Long = 1, Optional invert As Boolean = False) 

    Dim loopCounter As Long 
    Dim rowCounter As Long 
    Dim colCounter As Long 
    Dim endConsRow As Long 
    Dim tempArr As Variant 
    Dim toAdd As Long 
    Dim toHide As String 
    Dim sameVal As Boolean 
    Dim consBool As Boolean 
    Dim tempBool As Boolean 
    Dim rowStr As String 
    Dim goAhead As Boolean 
    Dim i As Long 

    If startRow > endRow Then 
     toAdd = endRow - 1 
    Else 
     toAdd = startRow - 1 
    End If 

    tempArr = ws.Range(ws.Cells(startRow, startCol), ws.Cells(endRow, endCol)).Value 

    ws.Rows(startRow & ":" & endRow).Hidden = False 

    loopCounter = 1 
    For rowCounter = LBound(tempArr, 1) To UBound(tempArr, 1) 
     For colCounter = LBound(tempArr, 2) To UBound(tempArr, 2) 
      sameVal = False 
      goAhead = False 
      If IsNumeric(valCrit) Then 
       If tempArr(rowCounter, colCounter) = valCrit Then 
        sameVal = True 
       End If 
      Else 
       If tempArr(rowCounter, colCounter) Like valCrit Then 
        sameVal = True 
       End If 
      End If 
      If sameVal Then 
       If invert = True Then 
        loopCounter = loopCounter + 1 
        Exit For 
       End If 
       goAhead = True 
      ElseIf colCounter = UBound(tempArr, 2) Then 
       If invert = False Then 
        loopCounter = loopCounter + 1 
        Exit For 
       End If 
       goAhead = True 
      End If 
      If goAhead = True Then 
       endConsRow = rowCounter 
       consBool = True 
       Do Until consBool = False 
        tempBool = False 
        For i = LBound(tempArr, 2) To UBound(tempArr, 2) 
         sameVal = False 
         If endConsRow = UBound(tempArr, 1) Then 
          Exit For 
         ElseIf IsNumeric(valCrit) Then 
          If tempArr(endConsRow + 1, i) = valCrit Then 
           sameVal = True 
          End If 
         Else 
          If tempArr(endConsRow + 1, i) Like valCrit Then 
           sameVal = True 
          End If 
         End If 
         If sameVal Then 
          If invert = False Then 
           endConsRow = endConsRow + 1 
           tempBool = True 
          End If 
          Exit For 
         ElseIf i = UBound(tempArr, 2) Then 
          If invert = True Then 
           endConsRow = endConsRow + 1 
           tempBool = True 
          End If 
         End If 
        Next 
        If tempBool = False Then 
         consBool = False 
        End If 
       Loop 
       rowStr = loopCounter + toAdd & ":" & endConsRow + toAdd 
       If toHide = "" Then 
        toHide = rowStr 
       ElseIf Len(toHide & "," & rowStr) > 255 Then 
        ws.Range(toHide).EntireRow.Hidden = True 
        toHide = rowStr 
       Else 
        toHide = toHide & "," & rowStr 
       End If 
       loopCounter = loopCounter + 1 + (endConsRow - rowCounter) 
       rowCounter = endConsRow 
       Exit For 
      End If 
     Next 
    Next 

    If Not toHide = "" Then 
     ws.Range(toHide).EntireRow.Hidden = True 
    End If 

End Sub