2017-08-31 106 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