this might be answered already from other posts I have read but still struggling to figure it out.
I have a workbook with 85 worksheets on it. Each sheet is like an invoice format, meaning it is not formatted as a normal data set. In order for me to get the data only I need, i created helper columns which only selects the data I need for consolidation. So I have a range I13:N42 which contains the data I need to consolidate.
At the end of the workbook, I already set up a Master Sheet with all the necessary headers for the data set. And there are 2 more worksheets namely "Tracking" & "AppControl" but I dont want them to be included in the loop together with the Master sheet.
For my range (filled with cell references/formulae), I need to copy only the row that has data in it.
You might have some ideas to improve the code I am currently using.
Sub Combine()
Dim i As Integer
Dim ws As Worksheet
Dim rng As Range
On Error Resume Next
For i = 1 To Sheets.Count
Sheets(i).Activate
Range("I13:N42").Select
Selection.Copy Destination:=Sheets("Master").Range("A65536").End(xlUp)(2)
Next i
End Sub
First remove On Error Resume Next. This line hides all error messages but the errors still occour, you just cannot see their messages. So if there are errors you cannot see you cannot fix them. If you don't fix them your code cannot work. Remove that line and fix your errors! Also see VBA Error Handling – A Complete Guide.
Second Avoid using Select in Excel VBA. That is a very bad practice and makes your code unreliable!
Option Explicit
Public Sub Combine()
Dim wsMaster As Worksheet ' set master worksheet
Set wsMaster = ThisWorkbook.Worksheets("Master")
Dim ExcludeWorksheets As Variant ' define worksheets names to exclude
ExcludeWorksheets = Array(wsMaster.Name, "Tracking", "AppControl")
Dim i As Long
For i = 1 To ThisWorkbook.Worksheets.Count
If Not IsInArray(ThisWorkbook.Worksheets(i).Name, ExcludeWorksheets) Then 'exclude these worksheets
ThisWorkbook.Worksheets(i).Range("I13:N42").Copy Destination:=wsMaster.Cells(wsMaster.Rows.Count, "A").End(xlUp)(2)
End If
Next i
End Sub
Public Function IsInArray(ByVal StringToBeFound As String, ByVal Arr As Variant) As Boolean
IsInArray = (UBound(Filter(Arr, StringToBeFound)) > -1)
End Function
Alternatively you can use a For Each loop which looks a bit cleaner then
Option Explicit
Public Sub Combine()
Dim wsMaster As Worksheet ' set master worksheet
Set wsMaster = ThisWorkbook.Worksheets("Master")
Dim ExcludeWorksheets As Variant ' define worksheets names to exclude
ExcludeWorksheets = Array(wsMaster.Name, "Tracking", "AppControl")
Dim ws As Worksheet
For Each ws Is ThisWorkbook.Worksheets
If Not IsInArray(ws.Name, ExcludeWorksheets) Then 'exclude these worksheets
ws.Range("I13:N42").Copy Destination:=wsMaster.Cells(wsMaster.Rows.Count, "A").End(xlUp)(2)
End If
Next ws
End Sub
Related
In my excel file I have a worksheet for every person. This worksheet is copied according a template sheet after entering data.
Now for the next part I would like to add data to a specific range on the sheet of that person.
Let's start with a simple date stamp to Range E4:E53 for the specified sheet. I'm using a combobox so you can select someone from the list and this is where i'm struggling;
After selecting someone from the list, my code does not write down the data.
As shown in the picture, the Worksheet is set to nothing. How do I set the worksheet according to the selected person from the combobox?
Public Sub CommandButton1_Click()
Dim lRow As String
Dim Rng As Range
Dim Rng2 As Range
Dim ws As Worksheet
Set ws = ComboBox1.List(I, 0)
Set Rng = Range("C4, C53")
Set Rng2 = Range("E4, Q53")
lRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
With ws
Rng.Cells.lRow.Value = Format(Time, "DD:MM:YYYY:HH:MM")
End With
End sub
I assume that your list contains names of worksheets for each person, like {"Monica", "Adam"...}, right?
The problem in your case is that you try to use string value from ComboBox1 to define worksheet which is an object in worksheets collection.
You should get string value (name) of worksheet and then use it to set your ws object.
Here is simple code snippet, hope it is what you wanted to achieve :)
Private Sub ComboBox1_click()
Dim ws As Worksheet
'Define worksheet from worksheets collection
Set ws = worksheets(ComboBox1.Value)
ws.Range("A5").Value = "Hello!"
End Sub
Private Sub UserForm_Initialize()
Dim ws As Worksheet
'Make list of all worksheets
For Each ws In worksheets
ComboBox1.AddItem ws.Name
Next ws
End Sub
I have a Macro (within a Master Workbook) that is getting data from another Workbook/Worksheet using .value2.
I've tried different changes, within the code. I double checked that both workbooks are open. However, I keep getting the Subscript out of range (Error 9).
Sub NielsenScorecard_DataPaste()
Dim WbNielsenScorecard As Workbook
Set WbNielsenScorecard = Workbooks("Nielsen Scorecard_Template.xlsm")
TotalUS_DataPaste
End Sub
Sub TotalUS_DataPaste()
**Subscript out of range (Error 9)**
With Workbooks("Power Query - Meijer_Walmart_Total US xAOC.xlsm").Worksheets("PQTotalUS")
Dim Data(0) As Variant
'Copy Data Range
Data(0) = .Range(.Cells(.Rows.Count, "A").End(xlUp), "AA2").Value2
End With
'Worksheet Code Name within this Workbook
With wsTotalUS
Debug.Print wsTotalUS.Name
.AutoFilter.ShowAllData
.Range("A2:AA" & .Cells(.Rows.Count, "A").End(xlUp).Offset(1).Row).ClearContents
With .Cells(.Rows.Count, "A").End(xlUp).Offset(1).Resize(UBound(Data(0)))
.Resize(ColumnSize:=UBound(Data(0), 2)).Value2 = Data(0)
End With
End With
End Sub
You can reference a sheet by its codename, however it is a different format and must be in ThisWorkbook. A drawback is that you cannot reference a sheet in another workbook by its codename. Worksheets("PQ Total US").Activate versus PQTotalUS.Activate. If your goal is to shorten the code and not have to repeat a long name, then another option is to do the following:
Dim wb1 as Workbook
Dim ws1 as Worksheet
Set wb1 = Workbooks("Power Query Meijer_Walmart_Total US xAOC.xlsm")
Set ws1 = wb1.Worksheets("PQ Total US")
With ws1
'Do something
End with
I have a team that works remotely on a shared spreadsheet. They can apply filters for search purposes. I would like the spreadsheet to be able to have the filters previously applied cleared automatically upon closing OR opening the spreadsheet without deleting the ability to set future filters. I cannot figure out the code to make this work.
I've searched these threads and tried many codes. Some have come close and have removed the filters when opening the spreadsheet, but it also removes the ABILITY to filter. This means that I have to turn on filtering each time I re-open the spreadsheet and that is not ideal. Code used is:
Private Sub Workbook_Open()
Dim ws As Worksheet
For Each ws In Worksheets
If ws.AutoFilterMode Then
ws.AutoFilterMode = False
End If
Next ws
End Sub
This will clear, but keep the filter:
Sub Workbook_Open()
Dim ws As Worksheet
For Each ws In Worksheets
If ws.AutoFilterMode Then
ws.AutoFilter.ShowAllData
End If
Next ws
End Sub
Another approach could be the following:
Sub clearFilter()
Dim sht As Worksheet 'Declare a worksheet variable
Dim rng As Range 'Declare a Range variable
Dim j As Long
Set sht = ThisWorkbook.Worksheets("Name of your Worksheet") 'The worksheet where the data is
Set rng = sht.Range("A:E") 'The range that is being filtered. In this case columns A,B,C,D,E are being filtered.
For j = 1 To rng.Columns.Count Step 1 'loop through all the columns that are being filtered...
rng.AutoFilter Field:=j '...and clear the filter while maintaining the filtering capabilities
Next j
End Sub
I am working on a macro that will cycle through all of the sheets in the active workbook and will then clear a certain part of a particular worksheet, based on whether one of the relevant keywords is contained in the worksheet name. In each case the worksheet name will be different, but any I want to clear will contain one of the key words below.
I have set up a separate macro to clear the range of cells in each case. If the Worksheet name does not contain any of the keywords, I want the macro to move onto the next worksheet.
My ultimate aim is to be able to apply this to numerous different workbooks, as the project I am working on is split by region, with a separate Excel file per region.
The code I have been trying is below. There are no errors appearing when I run the code, the code does not seem to run either, in fact nothing at all happens!
Any guidance or advice would be greatly appreciated.
Sub Loop_Customer_Sheets()
Dim ws As Integer
Dim i As Integer
ws = ActiveWorkbook.Worksheets.Count
For i = 1 To ws
If ActiveSheet.Name Like "*ABC*" Then
Call ABCInfoClear
ElseIf ActiveSheet.Name Like "*DEF*" Then
Call DEFInfoClear
ElseIf ActiveSheet.Name Like "*GHI*" Then
Call GHIInfoClear
Else:
End If
Next i
End Sub
"Nothing at all happens" - fixing the issue with your code:
Your issue is that you are looping through the number of sheets, but you are only checking the ActiveSheet, which never changes! Replace your code with
ws = ActiveWorkbook.Worksheets.Count
For i = 1 To ws
With ActiveWorkbook.WorkSheets(i)
If .Name Like "*ABC*" Then
ABCInfoClear
ElseIf .Name Like "*DEF*" Then
DEFInfoClear
ElseIf ActiveSheet.Name Like "*GHI*" Then
GHIInfoClear
End If
End With
Next i
Note: you don't need the Call keyword, you can just call subs as presented above.
Alternative solutions
A better option than having numerous macros might be to create a generic sub like
Sub ClearRangeInSheet(rangeAddress As String, sh As WorkSheet)
Dim myRange As Range
Set myRange = sh.Range(rangeAddress)
myRange.ClearContents
' Any other cell clearing code e.g. for formatting here
End Sub
Then call in the loop
Dim wsCount as Long
wsCount = ActiveWorkbook.WorkSheets.Count
For i = 1 to wsCount
With ActiveWorkbook
If .WorkSheets(i).Name Like "*ABC*" Then
' Always pass ".WorkSheets(i)", but change the range address as needed
ClearRangeInSheet("A1:A20", .WorkSheets(i))
ElseIf ' Other worksheet name conditions ...
End If
End With
Next I
As suggested in the comments, you could ditch indexing the sheets, and just loop through the sheet objects themselves:
Dim wksht as WorkSheet
For Each wksht In ActiveWorkbook.WorkSheets
If wksht.Name Like "*ABC*" Then
' Always pass wksht but change the range address as needed
ClearRangeInSheet("A1:A20", wksht)
ElseIf ' Other worksheet name conditions ...
End If
Next wksht
I'd like to find the position of a worksheet as it is displayed in a workbook.
For example, assume I have a workbook starting with Sheet1, Sheet2 and Sheet3 in that order. Then a user drags Sheet2 to left, before Sheet1.
I want Sheet2 to return 1, Sheet1 to return 2 (and Sheet3 still to return 3).
I can't find a way to determine this in VBA.
This should do it:
Worksheets("Sheet1").Index
https://msdn.microsoft.com/en-us/library/office/ff836415.aspx
You can just iterate the Worksheets collection of the Workbook object. You can test yourself by running the following code, switch the order around in the UI, then run it again:
Option Explicit
Sub IterateSheetsByOrder()
Dim intCounter As Integer
Dim wb As Workbook
Set wb = ThisWorkbook
For intCounter = 1 To wb.Worksheets.Count
Debug.Print wb.Worksheets(intCounter).Name
Next intCounter
End Sub
To loop through all worksheets in a workbook use For Each WS in ThisWorkbook.Worksheets where WS is a worksheet object. Hence to obtain order of Excel worksheets as shown, we may also use the following code:
Sub LoopThroughWorksheets()
Dim WS As Worksheet
For Each WS In ThisWorkbook.Worksheets
Debug.Print WS.Name
Next
End Sub
To obtain an output like Worksheets("Sheet1").Index then you may use this code
Sub IndexWorksheet()
Dim WS As Worksheet, n As Long
For Each WS In ThisWorkbook.Worksheets
n = n + 1
If WS.Name = "Sheet1" Then Debug.Print n
Next
End Sub
You can use the Sheets object. In your example, reading Sheets(2).Name should return Sheet1.
Right answer provided by Anastasiya-Romanova, but missing some important details.
There are two methods of doing this. First, with a For Each loop:
Sub ListSheetNames()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Debug.Print ws.Name
Next ws
End Sub
Second, with a basic For loop:
Sub ListSheetNames
Dim i As Long
For i = 1 to ThisWorkbook.Worksheets.Count
Debug.Print ThisWorkbook.Worksheets(i).Name
Next i
End Sub
You will find the second method will always output the names in the sheet index order, which is generally the order the sheets were created in unless you change the index. Simply rearranging the sheets from the workbook window won't change the index.
Therefore, the first method is the correct way to do this. It will always follow the tab order as you see on your screen.
Below code works even if sheet is renamed or its sequence is changed.
Sub Display_Sheet_Tab_Number()
Dim WorksheetName As String
Dim n As Integer
WorksheetName = Sheet1.Name
MsgBox Worksheetname
n = Sheets(WorksheetName).Index 'n is index number of the sheet
MsgBox "Index No. = " & n
End Sub