Faster way of hiding rows in vba - vba

Is there a faster, or more practical way of hiding rows in all sheets that have a zero value in column A? I have set up multiple macros to hide the rows, but this takes about 50-70 secs to complete any faster way?
Sub Macro14()
Dim c As Range
For Each c In Sheets("Main").Range("A200:A500")
If c.value = 0 Then
Sheets("Main").Rows(c.Row).Hidden = True
Else
Sheets("Main").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro15()
Dim c As Range
For Each c In Sheets("Elkhart East").Range("A50:A300")
If c.value = 0 Then
Sheets("Elkhart East").Rows(c.Row).Hidden = True
Else
Sheets("Elkhart East").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro16()
Dim c As Range
For Each c In Sheets("Tennessee").Range("A50:A300")
If c.value = 0 Then
Sheets("Tennessee").Rows(c.Row).Hidden = True
Else
Sheets("Tennessee").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro17()
Dim c As Range
For Each c In Sheets("Alabama").Range("A50:A300")
If c.value = 0 Then
Sheets("Alabama").Rows(c.Row).Hidden = True
Else
Sheets("Alabama").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro18()
Dim c As Range
For Each c In Sheets("North Carolina").Range("A50:A300")
If c.value = 0 Then
Sheets("North Carolina").Rows(c.Row).Hidden = True
Else
Sheets("North Carolina").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro19()
Dim c As Range
For Each c In Sheets("Pennsylvania").Range("A50:A300")
If c.value = 0 Then
Sheets("Pennsylvania").Rows(c.Row).Hidden = True
Else
Sheets("Pennsylvania").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro20()
Dim c As Range
For Each c In Sheets("Texas").Range("A50:A300")
If c.value = 0 Then
Sheets("Texas").Rows(c.Row).Hidden = True
Else
Sheets("Texas").Rows(c.Row).Hidden = False
End If
Next
End Sub
Sub Macro21()
Dim c As Range
For Each c In Sheets("West Coast").Range("A50:A300")
If c.value = 0 Then
Sheets("West Coast").Rows(c.Row).Hidden = True
Else
Sheets("West Coast").Rows(c.Row).Hidden = False
End If
Next
End Sub

This should do it in a pretty fast way:
Sub test()
Dim x As Variant, i As Long, j(1) As Long, rngVal As Variant, rnghide As Range, rngshow As Range, sht As Object
For Each sht In ActiveWorkbook.Sheets(Array("Main", "Elkhart East", "Tennessee", "Alabama", "North Carolina", "Pennsylvania", "Texas", "West Coast"))
Set rnghide = Nothing
Set rngshow = Nothing
If sht.Name = "Main" Then
j(0) = 200
j(1) = 500
Else
j(0) = 50
j(1) = 300
End If
x = sht.Range("A1:A" & j(1)).Value
For i = j(0) To j(1)
If x(i, 1) = 0 Then
If rnghide Is Nothing Then Set rnghide = sht.Rows(i) Else Set rnghide = Union(rnghide, sht.Rows(i))
Else
If rngshow Is Nothing Then Set rngshow = sht.Rows(i) Else Set rngshow = Union(rngshow, sht.Rows(i))
End If
Next
rnghide.EntireRow.Hidden = True
rngshow.EntireRow.Hidden = False
Next
End Sub
It simply runs each sheet for the whole range and stores the rows to show/hide in seperate ranges and then change there status in one step (1 for show and 1 for hide for each sheet)
If you have any questions or get any errors just tell me (can't test it right now)

Use an array:
Sub t()
Dim sheetArray() As Variant
Dim ws&, finalRow&, startRow&
Dim c As Range
sheetArray = Array("Alabama", "North Carolina", "West Coast")
For ws = LBound(sheetArray) To UBound(sheetArray)
If sheetArray(ws) = "Main" Then
startRow = 200
finalRow = 500
Else
startRow = 50
finalRow = 300
End If
For Each c In Sheets(sheetArray(ws)).Range("A" & startRow & ":A" & finalRow)
If c.Value = 0 And Not IsEmpty(c) Then
Sheets(sheetArray(ws)).Rows(c.Row).Hidden = True
Else
Sheets(sheetArray(ws)).Rows(c.Row).Hidden = False
End If
Next c
Next ws
End Sub
Just add to that array and it should work a little faster for you. If you have a ton of sheets, and don't want to manually type them into the VBA code, you can always set the array to the range of sheet names, then just go from there. Let me know if you need help doing so.
This also assumes you don't want to just loop through the workbook. If so, you can just do For each ws in ActiveWorkbook instead of lBound()...
Edit: I added some code to check the sheet, so it'll correctly adjust your ranges.

use this :
For Each ws In ActiveWorkbook.Worksheets
For Each c In ws.Range(IIf(ws.Name = "Main", "A200:A500", "A50:A300"))
ws.Rows(c.Row).Hidden = c.Value = 0
Next
Next
if you want exclude sheet Raw,Main and Calendar :
Dim untreatedSheet As Variant
untreatedSheet = Array("Raw", "Main", "Calendar")
For Each ws In ActiveWorkbook.Worksheets
If Not (UBound(Filter(untreatedSheet, ws.Name)) > -1) Then
For Each c In ws.Range("A50:A300")
ws.Rows(c.Row).Hidden = c.Value = 0
Next
End If
Next

This will work if you select all the sheets you want filtered FIRST:
Sub HideRows()
Dim ws As Worksheet
sAddress = "A:A"
For Each ws In ActiveWindow.SelectedSheets
ws.Range(sAddress).AutoFilter Field:=1, Criteria1:="<>0"
Next ws
End Sub

Related

Hiding columns from 2 ranges

I have to hide columns when a range is empty, and I have 2 ranges in different sheets to control when to hide or unhide these columns.
I'm trying to use a FOR loop with 2 variables, but i's not working, this is my code:
Sub HiddenColumns()
Dim HiddenColumn1 As Range
Dim HiddenColumn2 As Range
Dim c As Range
Dim d As Range
Set HiddenColumn1 = Range("rngColumnHidden")
Set HiddenColumn2 = Range("rngColumnHidden2")
For Each c In HiddenColumn1
For Each d In HiddenColumn2
If c.Value = "" Then
c.EntireColumn.Hidden = True
If d.Value = "" Then
d.EntireColumn.Hidden = True
End If
End If
Next d
Next c
End Sub
With one range it's working perfectly, but when I try to hide another range, I have problems, this is the code for one range:
Sub HiddenColumns()
Dim HiddenColumn1 As Range
Dim c As Range
Set HiddenColumn1 = Range("rngColumnHidden")
For Each c In HiddenColumn1
If c.Value = "" Then
c.EntireColumn.Hidden = True
End If
Next c
End Sub
edited after OP's comment
don't nest loops
Sub HiddenColumns()
Dim c As Range
For Each c In Range("rngColumnHidden").Rows(1).Cells
c.EntireColumn.Hidden = (c.Value = "")
Next c
For Each c In Range("rngColumnHidden2").Rows(1).Cells
c.EntireColumn.Hidden = (c.Value = "")
Next c
End Sub
and for the sake of avoiding code repetitions you could use a helper sub and code
Sub HiddenColumns()
HideColumns Range("rngColumnHidden")
HideColumns Range("rngColumnHidden2")
End Sub
Sub HideColumns(columnsRng As Range)
Dim c As Range
For Each c In columnsRng.Rows(1).Cells
c.EntireColumn.Hidden = (c.Value = "")
Next c
End Sub

VBA EXCEL - Small code optimization for on-worksheet open macro

I am looking to speed up an on-worksheet open macro I have in excel.
Every time the worksheet is opened, I would like it to autofit x rows and then hide any rows that have a 0 in it.
The macro works fine, but I think there must be a better/faster way to hide all relevant rows. Any help would be appreciated.
Private Sub Worksheet_Activate()
Rows("14:859").EntireRow.AutoFit
Application.ScreenUpdating = False
Dim c As Range
For Each c In Range("O1:O859").Cells
If c.Value = "0" Then
c.EntireRow.Hidden = True
End If
Next c
Application.ScreenUpdating = True
End Sub
Try this version:
Option Explicit
Private Sub Worksheet_Activate()
Const LAST_ROW = 859
Const CL = 15 'O column
Const RO = 14
Const HIDE_ROWS = True 'or False
Dim ur As Variant, hr As Range, R As Long
Application.ScreenUpdating = False
Rows(RO & ":" & LAST_ROW).EntireRow.AutoFit
ur = Range(Cells(1, CL), Cells(LAST_ROW, CL))
For R = 1 To LAST_ROW
If Len(ur(R, 1)) = 0 Then Exit For
If ur(R, 1) = 0 Then
If hr Is Nothing Then Set hr = Cells(R, 1) Else: Set hr = Union(hr, Cells(R, 1))
End If
Next
hr.EntireRow.Hidden = HIDE_ROWS
Application.ScreenUpdating = True
End Sub

Modifying existing loop when no instance of matched criteria is present

I've included the base code that currently runs to essentially pull out info for a specific product category based on a larger master listing (approx. 4000 lines by 36 columns). Previously this was not an issue, as the only codes listed and pulled out to individual sheets, were all is use; over time though, some of the older assigned product numbers are being discontinued and no longer in use. All I'm trying to do is modify the existing structure so that it first does a sweep through the master listing to verify whether or not any lines match the c.Value and d.Value - if there are no lines that meet the matching c.Value and d.Value criteria then it should just perform the action in the If statement inside the loop (ie. delete the old sheet, make a new one, and populate "G2" with a generic "item code not located" value); if any lines are found that meet the c and d.value criteria then it goes through the normal process.
Option Explicit
Sub Item()
CreateDeptReport "Item"
End Sub
Sub CreateDeptReport(Item As String)
Dim shtRpt As Excel.Worksheet, shtMaster As Excel.Worksheet, shtPrevious As Excel.Worksheet
Dim LCopyToRow As Long
Dim LCopyToCol As Long
Dim LastRow As Long
Dim arrColsToCopy
Dim c As Range, d As Range, e As Range, x As Integer
On Error GoTo Err_Execute
Application.ScreenUpdating = False
arrColsToCopy = Array(1, 8, 3, 7, 9, 10, 39, 19, 24, 25, 27, 29, 33, 34, 35)
Set shtMaster = ThisWorkbook.Sheets("CurrentMaster")
Set shtPrevious = ThisWorkbook.Sheets("PreviousMaster")
Set c = shtMaster.Range("AI5")
Set d = shtMaster.Range("H5")
Set e = shtMaster.Range("X5")
LCopyToRow = 11
Do
If c.Value = 2516 And d.Value = "37A" And Not e.Value = "T1" And Not e.Value = "T3" Then
If shtRpt Is Nothing Then
On Error Resume Next
Application.DisplayAlerts = False
ThisWorkbook.Sheets("Item").Delete
Application.DisplayAlerts = True
On Error GoTo 0
ThisWorkbook.Sheets("Template").Visible = xlSheetVisible
ThisWorkbook.Sheets("Template").Copy After:=shtPrevious
Set shtRpt = ThisWorkbook.Sheets(shtPrevious.Index + 1)
shtRpt.Name = Item
Range("G2").Value = "Item"
Range("C3").Value = Date
ThisWorkbook.Sheets("Template").Visible = xlSheetVeryHidden
End If
LCopyToCol = 1
shtRpt.Cells(LCopyToRow, LCopyToCol).EntireRow.Insert Shift:=xlDown
For x = LBound(arrColsToCopy) To UBound(arrColsToCopy)
shtRpt.Cells(LCopyToRow, LCopyToCol).Value = c.EntireRow.Cells(arrColsToCopy(x)).Value
LCopyToCol = LCopyToCol + 1
Next x
LCopyToRow = LCopyToRow + 1
End If
Set c = c.Offset(1, 0)
Set d = d.Offset(1, 0)
Set e = e.Offset(1, 0)
Loop Until IsEmpty(c.Offset(0, -1))
ThisWorkbook.Worksheets("Item").Rows("10:10").Delete
LastRow = Cells(Rows.Count, "A").End(xlUp).Row + 1
If LastRow <> 0 Then
Rows(LastRow).EntireRow.Delete
End If
Range("A9").Select
Application.ScreenUpdating = True
Exit Sub
Err_Execute:
MsgBox "An error occurred."
End Sub
It seems to me that you always want a new Worksheet for the Item.
So create the new worksheet first, then run the routine to find and fill the new worksheet with the records from the Master worksheet and use a variable (Dim blItmFound As Boolean) to flag when any record is found and at the end if there where no records found then enter in the new worksheet at G2 the generic string you want (see Rem Validate Records).
Please note that I changed "Item" for the value of the Variable Item and also changed this line:
Loop Until IsEmpty(c.Offset(0, -1))
for this:
Loop Until c.Value = Empty
for more details see IsEmpty Function
This is your code adjusted:
Sub CreateDeptReport(Item As String)
Dim shtRpt As Excel.Worksheet, shtMaster As Excel.Worksheet, shtPrevious As Excel.Worksheet
Dim LCopyToRow As Long
Dim LCopyToCol As Long
Dim LastRow As Long
Dim arrColsToCopy
Dim c As Range, d As Range, e As Range, x As Integer
Dim blItmFound As Boolean
arrColsToCopy = Array(1, 8, 3, 7, 9, 10, 39, 19, 24, 25, 27, 29, 33, 34, 35)
Application.ScreenUpdating = False
Set shtMaster = ThisWorkbook.Sheets("CurrentMaster")
Set shtPrevious = ThisWorkbook.Sheets("PreviousMaster")
Set c = shtMaster.Range("AI5")
Set d = shtMaster.Range("H5")
Set e = shtMaster.Range("X5")
Rem Delete Item Worksheet
On Error Resume Next
Application.DisplayAlerts = False
ThisWorkbook.Sheets(Item).Delete
Application.DisplayAlerts = True
On Error GoTo Err_Execute
Rem Add New Item Worksheet
ThisWorkbook.Sheets("Template").Visible = xlSheetVisible
ThisWorkbook.Sheets("Template").Copy After:=shtPrevious
Set shtRpt = ThisWorkbook.Sheets(shtPrevious.Index + 1)
shtRpt.Name = Item
Range("G2").Value = Item
Range("C3").Value = Date
ThisWorkbook.Sheets("Template").Visible = xlSheetVeryHidden
Rem Get Records from Master
LCopyToRow = 11
blItmFound = False
Do
If c.Value = 2516 _
And d.Value = "37A" _
And Not e.Value = "T1" _
And Not e.Value = "T3" Then
blItmFound = True
LCopyToCol = 1
shtRpt.Cells(LCopyToRow, LCopyToCol).EntireRow.Insert Shift:=xlDown
For x = LBound(arrColsToCopy) To UBound(arrColsToCopy)
shtRpt.Cells(LCopyToRow, LCopyToCol).Value = c.EntireRow.Cells(arrColsToCopy(x)).Value
LCopyToCol = LCopyToCol + 1
Next x
LCopyToRow = LCopyToRow + 1
End If
Set c = c.Offset(1, 0)
Set d = d.Offset(1, 0)
Set e = e.Offset(1, 0)
Loop Until c.Value = Empty
Rem Validate Records
Select Case blItmFound
Case True
ThisWorkbook.Worksheets(Item).Rows("10:10").Delete
LastRow = Cells(Rows.Count, "A").End(xlUp).Row + 1
If LastRow <> 0 Then
Rows(LastRow).EntireRow.Delete
End If
Case False
ThisWorkbook.Worksheets(Item).Range("G2").Value = "Item: [" & Item & "] code not located"
End Select
Range("A9").Select
Application.ScreenUpdating = True
Exit Sub
Err_Execute:
MsgBox "An error occurred."
End Sub
Based on what I've read, it sounds like you should just search for the values in their respective columns beforehand. This is also assuming that if one of those conditions is false, you'll enter your new code. So you could do something like:
Set cRange = shtMaster.Columns("AI:AI")
Set dRange = shtMaster.Columns("H:H")
If cRange.Find(2516) Is Nothing Or dRange.Find("37A") Is Nothing Then
'do code when either one of these conditions is false
Else
'both values are found in their respective columns
'do existing code
EDIT:
Set rng = Range("AI:AI")
Set origCell = rng.Find(2516)
Set currCell = origCell
Do
Set currCell = rng.FindNext(currCell)
If shtMaster.Range("H" & currCell.Row).Value = "37A" Then
boolMatchingPair = True
Exit Do
End If
Loop While currCell.Row <> origCell.Row
If boolMatchingPair = True
'found match
Else
'no match

How to put these lines into a single line?

How to put these lines into a single line ?
1,2,3,4......26
B2,C2,D2,.......Z2
Sheets("1").Range("B2:B300").Copy Sheets("Result").Range("B2")
Sheets("2").Range("B2:B300").Copy Sheets("Result").Range("C2")
Sheets("3").Range("B2:B300").Copy Sheets("Result").Range("D2")
Sheets("4").Range("B2:B300").Copy Sheets("Result").Range("E2")
Sheets("5").Range("B2:B300").Copy Sheets("Result").Range("F2")
.
.
.
Sheets("25").Range("B2:B300").Copy Sheets("Result").Range("Y2")
Sheets("26").Range("B2:B300").Copy Sheets("Result").Range("Z2")
Do a for loop:
For x = 1 to 26
Sheets(Cstr(x)).Range("B2:B300").Copy Sheets("Result").Cells(2,x+1)
next x
I think the following method helps to you
Sub GetCopyOfColumnB()
Dim ws As Worksheet
Dim resultPageName As String
Dim isTherePage As Boolean
Dim i As Integer
resultPageName = "Result"
isTherePage = False
For Each ws In ActiveWorkbook.Sheets
If ws.Name = resultPageName Then
isTherePage = True
End If
Next
If isTherePage = False Then
Worksheets.Add After:=Sheets(ActiveWorkbook.Sheets.Count)
Worksheets(Worksheets.Count).Name = resultPageName
End If
i = 1
For Each ws In ActiveWorkbook.Sheets
If ws.Name <> resultPageName Then
ws.Range("B2:B300").Copy Sheets("Result").Cells(2, i)
i = i + 1
End If
Next
End Sub

Loop through each column and delete columns with "0"

I'm not getting any errors but it's not deleting the columns with "0's". I just want to delete columns that have lots of 0's as you can read from my code. I'm not sure what could be wrong so any suggestions are welcome.
Sub Finalize()
Dim finalform As Worksheet
Dim deletename As String
Dim finalworkbook As Workbook
Dim ws As Worksheet
Dim copyrange As Range
Dim columnloop As Range
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Set finalform = Workbooks(ActiveWorkbook.Name).ActiveSheet
For a = 3 To 18
If Range("B" & a).Value <> "" Then
Workbooks.Open finalform.Range("B" & a).Value
Set finalworkbook = Workbooks(ActiveWorkbook.Name)
'Delete sheets
For b = 3 To 12
deletename = finalform.Range("D" & b).Value
If deletename <> "" Then
finalworkbook.Worksheets(deletename).Delete
End If
Next b
'Find, replace, remove
For Each ws In ActiveWorkbook.Worksheets
'Copy paste values
Set copyrange = ws.Cells
copyrange.Copy
copyrange.PasteSpecial xlPasteValues
Application.CutCopyMode = False
'Delete columns with 0
For Each columnloop In copyrange.Columns
d = 0
For c = 1 To 35
If Cells(c, columnloop.Column).Value = "0" Then
d = d + 1
End If
Next c
If d > 5 Then
columnloop.Delete
End If
Next columnloop
Next ws
End If
Next a
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Your loop can be replaced with more efficient methods of counting. You should always start at the extents when deleting rows or columns and work toward A1 in order that you do not skip over a column during the next incrementation.
Dim c As Long, ws As Worksheet
'Find, replace, remove
For Each ws In ActiveWorkbook.Worksheets
With ws
.UsedRange.Cells = .UsedRange.Cells.Value
'Delete columns with 0
For c = .UsedRange.Columns.Count To 1 Step -1
If Application.CountIf(.Columns(c), 0) > 5 Then
.Columns(c).EntireColumn.Delete
End If
Next c
End With
Next ws
There are several other areas that could be tweaked. Once this is running to an operational standard, consider posting it on Code Review (Excel) for further improvements.