Wondering why I can't do :
For i = 1 To ThisWorkbook.Sheets.Count
If ThisWorkbook.Sheets(i).Name <> "DO NOT SAVE" Then ThisWorkbook.Sheets(i).Select Replace:=False
Next i
Selection.Copy
what would be the best way to save all sheets which does not match DO NOT SAVE name in another wb ?
Try this:
Sub Tester()
Dim ws As Worksheet, arr(), i As Long
ReDim arr(0 To ThisWorkbook.Worksheets.Count - 2)
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "DO NOT SAVE" Then
arr(i) = ws.Name
i = i + 1
End If
Next ws
Worksheets(arr).Copy
End Sub
A Reflection on the Sheets' Visibility
To export a single sheet to a new workbook, the sheet has to be visible.
To export multiple sheets (using an array of sheet names) to a new workbook, at least one of the sheets has to be visible, while very hidden sheets will not get exported (no error though).
In a given workbook, the following procedure will copy all its sheets, except the ones whose names are in a given array (Exceptions), to a new workbook if at least one of the sheets is visible.
Before copying, it will 'convert' the very hidden sheets to hidden and after the copying, it will 'convert' the originals and copies to very hidden.
Option Explicit
Sub ExportSheets( _
ByVal wb As Workbook, _
ByVal Exceptions As Variant)
Dim shCount As Long: shCount = wb.Sheets.Count
Dim SheetNames() As String: ReDim SheetNames(1 To shCount)
Dim sh As Object
Dim coll As Object
Dim Item As Variant
Dim n As Long
Dim VisibleFound As Boolean
Dim VeryHiddenFound As Boolean
For Each sh In wb.Sheets
If IsError(Application.Match(sh.Name, Exceptions, 0)) Then
Select Case sh.Visible
Case xlSheetVisible
If Not VisibleFound Then VisibleFound = True
Case xlSheetHidden ' do nothing
Case xlSheetVeryHidden
If Not VeryHiddenFound Then
Set coll = New Collection
VeryHiddenFound = True
End If
coll.Add sh.Name
End Select
n = n + 1
SheetNames(n) = sh.Name
End If
Next sh
If n = 0 Then
MsgBox "No sheet found.", vbExclamation
Exit Sub
End If
If Not VisibleFound Then
MsgBox "No visible sheet found.", vbExclamation
Exit Sub
End If
If n < shCount Then ReDim Preserve SheetNames(1 To n) ' n - actual count
If VeryHiddenFound Then ' convert to hidden
For Each Item In coll
wb.Sheets(Item).Visible = xlSheetHidden
Next Item
End If
wb.Sheets(SheetNames).Copy ' copy to new workbook
If VeryHiddenFound Then ' revert to very hidden
Dim dwb As Workbook: Set dwb = Workbooks(Workbooks.Count)
For Each Item In coll
wb.Sheets(Item).Visible = xlSheetVeryHidden
dwb.Sheets(Item).Visible = xlSheetVeryHidden
Next Item
End If
MsgBox "Sheets exported: " & n, vbInformation
End Sub
Sub ExportSheetsTEST()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
ExportSheets wb, Array("DO NOT SAVE")
End Sub
Alternatively you could use the following snippet:
Sub CopyWorkbook()
Dim i As Integer
For i = 1 To ThisWorkbook.Sheets.Count
If ThisWorkbook.Sheets(i).Name <> "DO NOT SAVE" Then
Dim rng As Range
Windows("SOURCE WORKBOOK").Activate
rng = ThisWorkbook.Sheets(i).Cells
rng.Copy Before:=Workbooks("TARGET WORKBOOK").Sheets(i)
End If
Next i
End Sub
Related
I have a document with 500 + WorkSheets and trying to print all the ones where G1 = "Print" as a Single document.
My steps are to create an array and store the matching worksheet names. Next is to select that worksheets from the array and print them.
Sub Help()
Dim MyArray() As Variant
Dim I As Long
Dim MyArray_Count As Integer
MyArray_Count = 0
Worksheet_Count = ActiveWorkbook.Worksheets.Count
For I = 1 To Worksheet_Count
If Worksheets(I).Range("G1").Value = "Print" Then
MyArray_Count = MyArray_Count + 1
MyArray(MyArray_Count) = ActiveWorkbook.Worksheets(I).Name ' 'Having error here
End If
Next I
Worksheets(MyArray).Select 'having error here
End Sub
There are many ways to do this, but the important piece you are missing is Redim Preserve.
I changed a few things to keep it simple. I tried to stick closely to your design. As you can see, you also have to plan for what happens when none of them meet the condition.
Sub Help()
Dim ws As Worksheet
Dim MyArray() As String
ReDim MyArray(0)
For Each ws In ActiveWorkbook.Worksheets
If ws.Range("G1").Value = "Print" Then
If Len(MyArray(0)) > 0 Then ReDim Preserve MyArray(UBound(MyArray) + 1)
MyArray(UBound(MyArray)) = ws.Name
End If
Next
If Len(MyArray(0)) > 0 Then
ActiveWorkbook.Worksheets(MyArray).Select
Else
MsgBox "none found"
End If
End Sub
Note: Keep in mind that "Print" in your cell is not the same thing as "print" or "PRINT"
Here is a better If statement to address that:
If UCase$(Trim$(ws.Range("G1").Value)) = "PRINT" Then
Dictionary vs Array
Dictionary
You don't know how many worksheets will be added, therefore using the dictionary presents a more suitable (easier) solution. Also, using a For Each...Next loop makes it kind of more readable and emphasizes that the number of worksheets is not relevant.
Option Explicit
Sub HelpDictionary()
Dim wb As Workbook: Set wb = ActiveWorkbook
' If you're dealing with the workbook containing this code, instead use:
'Dim wb As Workbook: Set wb = ThisWorkbook
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
Dim ws As Worksheet
Dim cString As String
' Add the worksheet names to the dictionary.
For Each ws In wb.Worksheets
cString = CStr(ws.Range("G1").Value)
If StrComp(cString, "Print", vbTextCompare) = 0 Then ' 'PRINT = print'
dict(ws.Name) = Empty ' only interested in the keys
End If
Next ws
' Check if any worksheet name was added.
If dict.Count = 0 Then ' no worksheet name added
MsgBox "No worksheets to select.", vbExclamation
Exit Sub
'Else ' at least one worksheet name was added
End If
wb.Worksheets(dict.Keys).Select
MsgBox "The following worksheets are selected: " _
& vbLf & Join(dict.Keys, vbLf), vbInformation
End Sub
Array
This is also a valid solution. Compare it with the dictionary solution to see how it is more complicated.
Sub HelpArray()
Dim wb As Workbook: Set wb = ActiveWorkbook
' If you're dealing with the workbook containing this code, instead use:
'Dim wb As Workbook: Set wb = ThisWorkbook
Dim aCount As Long: aCount = wb.Worksheets.Count
Dim MyArray() As String: ReDim MyArray(1 To aCount) ' to fit 'a'll names
Dim cString As String
Dim a As Long ' 'a'll worksheets
Dim p As Long ' worksheets to 'p'rint
' Add the worksheet names to the array.
For a = 1 To aCount
cString = CStr(Worksheets(a).Range("G1").Value)
If StrComp(cString, "Print", vbTextCompare) = 0 Then ' 'PRINT = print'
p = p + 1
MyArray(p) = wb.Worksheets(a).Name
End If
Next a
' Check if any worksheet name was added.
If p = 0 Then ' no worksheet name added
MsgBox "No worksheets to select.", vbExclamation
Exit Sub
'Else ' at least one worksheet name was added
End If
' Resize if not all worksheet names.
If p < aCount Then ' not all worksheet names added
ReDim Preserve MyArray(1 To p)
'Else ' all worksheet names added
End If
wb.Worksheets(MyArray).Select
MsgBox "The following worksheets are selected: " _
& vbLf & Join(MyArray, vbLf), vbInformation
End Sub
I have put together the code below to hide named worksheets using a Checkbox. The workbook also contains sheets with the generic names like Sheet1, Sheet2, etc and I would like to be able to hide all sheets whose name contains the word "Sheet" from the same Checkbox.
Is this possible?
Thanks
Private Sub CheckBox1_Click()
Application.ScreenUpdating = False
If CheckBox1 = False Then
If ThisWorkbook.Sheets("Summary").Range("B10") <> "" Then Sheets(ActiveSheet.Range("B10").Value).Visible = False
Else:
If ThisWorkbook.Sheets("Summary").Range("B10") <> "" Then Sheets(ActiveSheet.Range("B10").Value).Visible = True
End If
Application.ScreenUpdating = False
End Sub
If you really want hiding sheets, please use the next code. It hides all sheets where their name starts with ""Sheet":
Private Sub CheckBox1_Click()
Dim sh As Worksheet
For Each sh In Worksheets
If left(sh.name, 5) = "Sheet" Then
sh.Visible = xlSheetVeryHidden
End If
Next
End Sub
Hide Worksheet With Pattern
Reminder
At least one of all sheets in a workbook has to be visible.
There is a third 'visibility' parameter xlSheetHidden which is not considered in this solution.
You can hide multiple worksheets in one go by using an array of worksheet names (fast), but you have to loop through the array to unhide each of them (slow).
The Code
Option Explicit
Private Sub CheckBox1_Click()
Const WorksheetPattern As String = "ShEeT*"
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsArr As Variant
Application.ScreenUpdating = False
If CheckBox1 Then ' Hide
wsArr = WorksheetNamesToArray(wb, WorksheetPattern)
wb.Worksheets(wsArr).Visible = xlSheetHidden ' also 0 or False
Else ' UnHide
wsArr = WorksheetNamesToArray(wb, WorksheetPattern, xlSheetHidden)
Dim n As Long
For n = 1 To UBound(wsArr)
wb.Worksheets(wsArr(n)).Visible = xlSheetVisible ' also -1 or True
Next n
End If
Application.ScreenUpdating = True
End Sub
Function WorksheetNamesToArray( _
ByVal wb As Workbook, _
ByVal WorksheetPattern As String, _
Optional ByVal isVisible As XlSheetVisibility = xlSheetVisible) _
As Variant
If Not wb Is Nothing Then
Dim wsCount As Long: wsCount = wb.Worksheets.Count
Dim wsArr() As String: ReDim wsArr(1 To wsCount)
Dim ws As Worksheet
Dim n As Long
For Each ws In wb.Worksheets
If UCase(ws.Name) Like UCase(WorksheetPattern) Then
If ws.Visible = isVisible Then
n = n + 1
wsArr(n) = ws.Name
End If
End If
Next ws
ReDim Preserve wsArr(1 To n)
WorksheetNamesToArray = wsArr
End If
End Function
I found this code below to help combine multiple sheets of data into one, however, it won't take from multiple sheets. I have two sheets and it either grabs one or the other. I tried to add on to it to specify more than one sheet but that doesn't seem to work either. How can I make this pull from multiple sheets? I have a sheet "anaheim" and sheet "Woodridge."
Sub Step3()
Dim i As Long
Dim xRg As Range
On Error Resume Next
Worksheets.Add Sheets(1)
ActiveSheet.Name = "MasterSheet"
For i = 2 To Sheets.Count
Set xRg = Sheets(1).UsedRange
If i > 2 Then
Set xRg = Sheets(1).Cells(xRg.Rows.Count + 1, 1)
End If
Sheets(i).Activate
ActiveSheet.UsedRange.Copy xRg
Next
End Sub
Sub Step3()
Dim sh As Worksheet
Dim xRg As Range
Sheets.Add.Name = "MasterSheet"
For Each sh In Sheets
If sh.Name <> "MasterSheet" Then
sh.UsedRange.Copy Sheets("MasterSheet").Cells(Sheets("MasterSheet").Rows.Count, "A").End(xlUp).Offset(1)
End If
Next
End Sub
Backup Used Ranges
Option Explicit
Sub backupUsedRanges()
' Target Worksheet
Const tgtSheetName As String = "MasterSheet"
Const tgtFirstCell As String = "A1"
' Workbook
Dim wb As Workbook
Set wb = ThisWorkbook ' The workbook containing this code.
' Check if a sheet named 'tgtSheetName' already exists.
Dim Msg As Variant
If SheetExists(wb, tgtSheetName) Then
Msg = MsgBox("A sheet named '" & tgtSheetName _
& "' already exists. Do you want to delete it?", _
vbYesNo + vbExclamation, "Delete?")
If Msg = vbYes Then
Application.DisplayAlerts = False
wb.Worksheets(tgtSheetName).Delete
Application.DisplayAlerts = True
Else
MsgBox "Backup NOT created.", vbExclamation, "Fail"
Exit Sub
End If
End If
' Define (add) Target Worksheet ('tgt').
Dim tgt As Worksheet
Set tgt = wb.Worksheets.Add(Before:=wb.Sheets(1))
tgt.Name = tgtSheetName
' Define Next Target First Available Cell Range ('cel').
Dim cel As Range
Set cel = tgt.Range(tgtFirstCell)
' Write from Source Worksheets ('src') to Target Worksheet.
Dim src As Worksheet ' Current Source Worksheet
Dim rng As Range ' Current Source Used Range
For Each src In wb.Worksheets
If StrComp(src.Name, tgtSheetName, vbTextCompare) <> 0 Then
' Define Current Source Used Range ('rng').
Set rng = src.UsedRange
' Copy Current Source Used Range to Target Worksheet.
rng.Copy cel
' Define Next Target First Available Cell Range.
Set cel = cel.Offset(rng.Rows.Count)
End If
Next src
' Inform user
MsgBox "Backup created.", vbInformation, "Success"
End Sub
Function SheetExists(Book As Workbook, SheetName As String) As Boolean
Dim sh As Object
For Each sh In Book.Sheets
If StrComp(sh.Name, SheetName, vbTextCompare) = 0 Then
SheetExists = True
Exit Function
End If
Next sh
End Function
Hi everyone! I'm trying to write a method in VBA to keep 2 worksheets and delete others at the same time.
I already did the one that will keep one worksheet and delete others like this:
Sub delete_all_pages_except_main()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Application.DisplayAlerts = False
If ws.Name <> "Home Page" Then
ws.Delete
End If
Next ws
End Sub
And I try to write it like this
If (ws.Name <> "Home Page" Or ws.Name <> "Data")
But VBA would accept it.
Can you guys help? Thank you.
This should do
Sub delete_all_pages_except_main()
Dim ws As Worksheet
Dim arr As Variant
Dim boo As Boolean
Application.DisplayAlerts = False
arr = Array("Home Page", "Data")
For Each ws In ThisWorkbook.Worksheets
boo = NoDel(ws.Name, arr)
If boo <> True Then ws.Delete
Next ws
Application.DisplayAlerts = True
End Sub
Function NoDel(ws As String, warr As Variant) As Boolean
NoDel = False
For i = LBound(warr, 1) To UBound(warr, 1)
If warr(i) = ws Then NoDel = True
Next i
End Function
Delete Sheets With Exceptions
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: In a specified workbook, writes all the sheet names '
' not specified in an Exceptions array to a Result array, and '
' using the Result array deletes all the sheets in one go. '
' Remarks: This solution applies to worksheets and chartsheets. '
' Since there is no Sheet object, the For Next loop (instead '
' of the For Each Next loop) and the Object type have '
' to be used. '
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub deleteSheets(Book As Workbook, Exceptions As Variant)
' Program
Dim SheetsCount As Long: SheetsCount = Book.Sheets.Count
Dim Result As Variant: ReDim Result(SheetsCount)
Dim sh As Object, i As Long, j As Long
j = -1
For i = 1 To SheetsCount: GoSub checkName: Next i
If j = -1 Then GoTo NothingToDelete
If j = SheetsCount - 1 Then GoTo NoExceptions
GoSub deleteSheetsInOneGo
MsgBox "Deleted '" & j + 1 & "' sheets.", vbInformation, "Success"
Exit Sub
' Subroutines
checkName:
Set sh = Book.Sheets(i)
If IsError(Application.Match(sh.Name, Exceptions, 0)) Then
j = j + 1
Result(j) = sh.Name
End If
Return
deleteSheetsInOneGo:
ReDim Preserve Result(j)
Application.DisplayAlerts = False
Book.Sheets(Result).Delete
Application.DisplayAlerts = True
Return
' Labels
NothingToDelete:
MsgBox "Sheets already deleted.", vbCritical, "Nothing to Delete"
Exit Sub
NoExceptions:
MsgBox "Cannot delete all sheets.", vbCritical, "No Exceptions"
Exit Sub
End Sub
' Usage Example
Sub runDeleteSheets()
Dim SheetNames As Variant: SheetNames = Array("Home Page", "Data")
deleteSheets ThisWorkbook, SheetNames
End Sub
I have a master workbook, which houses a group of 15 worksheets that house data for summary pivot tables and whatnot. Every week this master workbook gets updated with a daily report that has those 15 worksheets, but also around 20 other ones. I am just trying to get a script together to identify if they exist, and if so, to move that daily data to the master workbooks worksheet (only move data if daily wb worksheet exists in master workbook).
Here is a very general shell of what I'm trying to achieve, but I'm not well versed in determining the logic if a sheet exists, so my blnFound variable is obviously misplaced. I hope this shows a rough outline of what I'm trying to achieve. Any help is greatly appreciated!
Option Explicit
Sub Update_New_Data()
Const BasePath As String = "C:\\User\Data..."
Dim wbMaster As Workbook: Set wbMaster = ThisWorkbook
Dim wbNewData As Workbook: Set wbNewData = Workbooks.Open(BasePath & "\03.01.20.xlsx")
Dim wsMaster As Sheet
Dim blnFound As Boolean
'places all sheet names into array
With wbNewData
Dim varWsName As Variant
Dim i As Long
Dim ws As Worksheet
ReDim varWsName(1 To wbNewData.Worksheets.Count - 2)
For Each ws In wbNewData.Worksheets
Select Case ws.Name
Case "Inputs", "Data --->>>"
Case Else
i = i + 1
varWsName(i) = ws.Name
End Select
Next
End With
'if wbNewData sheet name is found in wbMaster
'then locate it and place wbNewData data into that sheet
With wbMaster
For Each wsMaster In wbMaster.Sheets
With wsMaster
If .Name = varWsName(i) Then
blnFound = True
wbNewData(Worksheets(i)).UsedRange.Copy Destination:=wbMaster(Worksheets(i)).Range("A1")
Else: blnFound = False
End If
End With
Next
End With
End Sub
To check if something exists you can use a Dictionary Object
Option Explicit
Sub Update_New_Data()
Const BasePath As String = "C:\\User\Data..."
Dim wbMaster As Workbook, wbNewData As Workbook
Set wbMaster = ThisWorkbook
Set wbNewData = Workbooks.Open(BasePath & "\03.01.20.xlsx", , False) ' read only
Dim ws As Worksheet, sKey As String, rng As Range, msg As String
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
'places all master sheet names into dictionary
For Each ws In wbMaster.Sheets
If ws.Name = "inputs" Or ws.Name = "Data --->>>" Then
' skip
Else
dict.Add CStr(ws.Name), ws.Index
Debug.Print "Added to dict", ws.Index, ws.Name
End If
Next
' if wbNewData sheet name is found in wbMaster
' then locate it and place wbNewData data into that sheet
For Each ws In wbNewData.Sheets
sKey = CStr(ws.Name)
If dict.exists(sKey) Then
' clear master
wbMaster.Sheets(dict(sKey)).cells.clear
Set rng = ws.UsedRange
rng.Copy wbMaster.Sheets(dict(sKey)).Range("A1")
msg = msg & vbCr & ws.Name
Else
Debug.Print "Not found in master", ws.Index, ws.Name
End If
Next
wbNewData.Close
' result
If Len(msg) > 0 Then
MsgBox "Sheets copied were " & msg, vbInformation
Else
MsgBox "No sheets copied", vbExclamation
End If
End Sub