I have the following simple Excel spreadsheet:
A
1 Sheet1 =MID(CELL("filename",Sheet1!K1),FIND("]",CELL("filename",Sheet1!K1))+1,255)
2 Sheet2 =MID(CELL("filename",Sheet2!K1),FIND("]",CELL("filename",Sheet2!K1))+1,255)
3 Sheet3 =MID(CELL("filename",Sheet3!K1),FIND("]",CELL("filename",Sheet3!K1))+1,255)
4 Sheet4 =MID(CELL("filename",Sheet4!K1),FIND("]",CELL("filename",Sheet4!K1))+1,255)
5 Sheet5 =MID(CELL("filename",Sheet5!K1),FIND("]",CELL("filename",Sheet5!K1))+1,255)
6
7
In Column A there is a list of all sheets in the Excel file. I list the sheets using the formula that you can see next to it.
All this works fine so far.
Now it can happen that some sheets in my spreadsheet are invisible (hidden). In this case I want that those sheets do not appear in the list above. Therefore, I wonder if there is a formula that can identify if a sheet is visible or not. Something like this:
IF MID(CELL("filename",Sheet1!K1),FIND("]",CELL("filename",Sheet1!K1))+1,255) = Invisible THEN ""
Do you have any idea how to solve this issue?
I don't really understand the purpose of this list... it seems like you're just duplicating the list of worksheet "tabs" shown at the bottom of the screen.
I sense something being made more complicated than necessary; either an XY Problem, or some duplicate data that you're trying to manage without reorganizing it. :-)
Regardless, based on my understanding of your question, there are no built-in functions to do what you need, but these VBA examples should give you some ideas:
This procedure lists all visible worksheets, in the Immediate Window (Hit Ctrl+G from VBA to view it):
Sub ListSheets() 'list in immediate window
Dim sht As Worksheet
For Each sht In Worksheets
If sht.Visible = xlSheetVisible Then Debug.Print sht.Name
Next sht
End Sub
This procedure is similar excep lists them on the active worksheet, leaving blanks for hidden sheets (like your example would imply):
Sub ListSheets() 'list on worksheet
Dim sht As Worksheet
For Each sht In Worksheets
If sht.Visible = xlSheetVisible Then Range("A" & sht.Index) = sht.Name
Next sht
End Sub
This function can be called from a worksheet formula and lists the name of the worksheet you specify by index number. It returns "" (empty string/nothing) if the worksheet is not set to Visible, or if it doesn't exist.
Function listSheet(shtNum As Long) As String
On Error Resume Next
If Sheets(shtNum).Visible = xlSheetVisible Then listSheet = Sheets(shtNum).Name
End Function
Related note:
There are three types of worksheet visibility.
More Info:
MSDN: Worksheet.Visible Property (Excel)
Related
I am trying to unhide a group of worksheets if they meet a certain condition. This uses a user form, triggered by a command button, with selection options and another command button. The expected behavior is that once the selection has been made and the button has been pressed, all worksheets meeting the criteria will be unhidden. The Target word is present at different locations along the first row and all cells before it are empty on that row. Ideally, the process will scan each cell in the first row of each worksheet in the workbook until it comes across the Target, unhide the worksheet, then move on to the next worksheet to start the process over again until all worksheets with the workbook have been checked.
Upon activation of the command button on the user form I have the following:
Private Sub ContinueCommand_Click()
Dim Valid As Boolean, wks As Worksheet, c As Integer, actCol As Long
actCol = ActiveSheet.Range("A1").End(xlToRight).Column
For Each wks In ActiveWorkbook.Worksheets
For c = 1 To actCol
If ActiveCell.Value = "Target" Then
wks.Visible = xlSheetVisible
Exit For
End If
Next c
Next wks
Valid = True
If Valid = True Then
Unload Me
End If
End Sub
I've borrowed from several sources, including here for using ActiveCell, determining if a value exists, unhidding worksheets, Finding values within a range, and searching for a string. Any help would be greatly appreciated.
As I said in my comments there are some issues with the way you've chosen to implement this.
Your For c = 1 To actCol loop is not needed. This can be easily seen because c is not really used anywhere in the loop.
Let's assume your Target value is in wks.Range("A100") (the 1st row and 100th column).
Your code would then perform the exact same operation 100 times and would come up with the exact same result. That's what leads you to use Exit For, which is a bad practice.
If I understood your initial post correctly, if Target exists in a particular worksheet, then all cells before Target are empty.
If that's the case, the Target will either be in wks.Range("A1") or in wks.Range("A1").End(xlToRight). If it's not in either of these two cells then it doesn't exist at all in this particular worksheet, which would mean that the 1st row is completely empty. You don't need to check any more cells apart from these two.
Your code does not check whether Target is in wks.Range("A1").
Also your use of Application.Match, makes me believe that you have probably been misled by the common misconception that wks.Range("A1").End(xlToRight) is a range of cells starting from A1 and extending all the way to the last non-empty cell in the 1st row.
The truth is that wks.Range("A1").End(xlToRight) is a single cell rather than a range of cells. Selecting A1 and then pressing CTRL+right arrow, will show you exactly which cell it is.
I might be missing something, but according to your description in the initial post, I would do something like the following:
Dim sht As Worksheet
For Each sht In ThisWorkbook.Worksheets
If sht.Range("A1").Value = "Target" Or sht.Range("A1").End(xlToRight).Value = "Target" Then
sht.Visible = xlSheetVisible
Else
MsgBox "target was not found in " & sht.Name
End If
Next sht
I want to thank BruceWayne, Scott Craner, Stavros Jon, Darell H whom all helped me get closer to this answer. The final result looked like this:
Private Sub ContinueCommand_Click()
Dim wks As Worksheet
For Each wks In ActiveWorkbook.Worksheets
If Not IsError(Application.Match("Target", wks.Range("A1").End(xlToRight), 0)) Then
wks.Visible = xlSheetVisible
End If
Next wks
Unload Me
End Sub
If anyone in the future has issues getting this to work, let me know and I will post a more complete version.
I have 200 worksheets (named 1, 2, 3 and so on) that i need to loop through and copy and paste varying ranges of data from each one into a master worksheet. How can i do this?
I have a list of all the sheets in an array in the VB Editor and have tried to loop through it.
I have a list of the sheet names in a table in another worksheet and have tried to loop through it as well.
Can someone provide a simple example of how one of these methods can be done?
Example code shown below.
Dim i As Integer
i = 11
Dim SheetList As String
Dim element As Variant
SheetList = Array("Sheet24", "Sheet25")
'Simplified example of Do While loop being used
Do While Sheet1.Cells(i, 2).Value <> ""
For Each element In SheetList
If element.Range("C3") = "" Then
GoTo Next Iteration
Else
'copy and paste data in master worksheet
End If
NextIteration:
i = i +1
Next element
Loop
Expected result: ranges of data from a number of worksheets to be copy and pasted into one combined range on the master worksheet.
You can easily loop through all the worksheets in a workbook, without needing their names, using:
Dim sht As Worksheet
For Each sht In ThisWorkbook.Worksheets
'do something
Next sht
If the range you need to copy is different in every worksheet, then you could search for the headers of the columns you want to copy for example, get the range you need and paste it's contents to your master worksheet.
If there are specific sheets you want to use, then you could still loop through all the sheets and check if some condition is true for a specific sheet like so:
For Each sht In ThisWorkbook.Worksheets
If sht.Name = "something" Then
'do something
End If
If Condition Then
'do something
End If
Next sht
For example the sheets from which you want to copy some data, could have a "flag" cell with a specific value assigned to it, like TRUE or 1. The code would check for the contents of this cell and act accordingly.
Now if you want to save time by not looping through all the sheets (which shouldn't take too much time anyway..) and to avoid checking a condition for each sheet, then you could create a custom collection of worksheets, consisting of only those sheets you are interested in.
Dim sht As Worksheet
Dim shtcol As New Collection
shtcol.Add ThisWorkbook.Worksheets(1)
shtcol.Add ThisWorkbook.Worksheets(2)
shtcol.Add ThisWorkbook.Worksheets(3)
For Each sht In shtcol
'do something
Next sht
I have set up a VBA macro that is running a VBA operation consecutively in each spreadsheet of a given Excel file. Given that there are numerous sheets in the file, which leads to occasional interruptions with the server, I have to restart the request every once in a while.
So here comes the question: I am looking to modify the code element below in a way that the VBA macro starts running on the currently selected sheet/tab. It shall then consecutively cover all remaining sheets/tabs to the right of the active sheet, but not those to the left which have already been populated.
The code below restarts the each run of the macro with the very first sheet/tab of the file, which is not necessary. Is there any smart tweak to the code?
Dim xsheet As Worksheet
For Each xsheet In ThisWorkbook.Worksheets
xsheet.Select
There are three sheet-specific collections: Worksheets, Charts and DialogSheets. The Index property of these collections returns Sheets's collection index - not the actual index in sheet-specific collection.
Say, you have four sheets:
Worksheet ("Sheet1")
Worksheet ("Sheet2")
Chart ("Chart1")
Worksheet ("Sheet3").
In this case Worksheets("Sheet3").Index returns 4 when the real index is 3. The bottom line is never rely on Index property of sheet-specific collection when it comes to processing all the sheets.
To solve you problem you just need to use Sheets collection:
Sub FFF()
Dim x%, sheet As Variant
For x = ActiveSheet.Index + 1 To Sheets.Count
Set sheet = Sheets(x)
'// Do something with sheet
Next
End Sub
Continue Through Worksheets
If you want to continue with the ActiveSheet, just remove ' + 1'.
Warning: These codes are valid if you only have worksheets in the workbook, and not charts, dialogs or whatever.
I almost always use only worksheets in my workbooks so I never learned about the Index issue that JohnyL is referring to in his answer to this question.
The Idea
Sub ContinueThroughWorksheets()
Dim i As Long
With ThisWorkbook
For i = .ActiveSheet.Index + 1 To .Worksheets.Count
Debug.Print .Worksheets(i).Name
Next
End With
End Sub
The Implementation
Sub ContinueThroughWorksheets2()
Dim i As Long
Dim j As Long
With ThisWorkbook
Select Case .ActiveSheet.Index
Case 1
j = 1
Case .Worksheets.Count
Exit Sub
Case Else
j = .ActiveSheet.Index + 1
End Select
For i = j To .Worksheets.Count
Debug.Print .Worksheets(i).Name
Next
End With
End Sub
You can do it thus, but note that it's generally not advisable to base code on the active sheet or active cells as they can easily be changed and your code may not run correctly.
A better method would be to store the (code)names of the sheets processed elsewhere and loop through your sheets excluding those names.
Sub x()
Dim i As Long
For i = ActiveSheet.Index To Worksheets.Count
MsgBox Worksheets(i).Name
Next i
End Sub
I have an excel workbook that contains multiple sheets. In this workbook sheets occasionally are removed, renamed, or added. This workbook features a sheet (Sheet1) that is supposed to be used as a command center for printing copies of the other sheets in the workbook. Unfortunately, this printing command center does not work as intended.
The command center has only two columns. In column A is a list with the names of the other Sheets. In column B the user can specify how many copies to print of the respective sheet in column A.
This is the current code:
Sub PrintSheets()
Dim mysheets As Range
For Each mySheets In Sheet1.Range("A2:A100")
If mySheets.Offset(0, 1).Value <> "" Then Sheets(mySheets.Value).PrintOut Copies:=mySheets.Offset(0, 1).Value
Next mySheets
End Sub
The first two sheets are printed as intended and then I get a "Run-time error '9': Subscript out of range"
1) How can I fix the error?
2) Can the list with the sheet names be generated automatically and sorted by their position (i.e., left to right in the sheet tab -> top to bottom in the column)?
If you rename, add and remove sheets, you will have to update your list before printing. This sub will clear Range("A2:A100") and it will insert all sheets names in your first sheet. Make sure your "command center" sheet is the first one (or change the index reference to the name of that special sheet).
Sub LIST_SHEETS()
Application.ScreenUpdating = False
Dim ws As Worksheet
Dim i As Byte
ThisWorkbook.Sheets(1).Range("A2:A100").Clear
i = 2
For Each ws In ThisWorkbook.Sheets
ThisWorkbook.Sheets(1).Range("A" & i).Value = ws.Name
i = i + 1
Next ws
Application.ScreenUpdating = True
End Sub
I'm afraid you will have to figure out where to put the code. I don't know your needs, so maybe after renaming/adding/deleting all sheets, or maybe when Workbook opens or something like that. Try it!.
It appears that a name in the list of sheets, does not exactly match the actual name. You can use either of the two options below, to loop through each sheet
For Each sht in ThisWorkbook.Sheets
'Do Something
Next
Or
Dim sht as Worksheet
For i= 0 to ThisWorkbook.Sheets.Count
Set sht=ThisWorkbook.Sheets(i)
'Do something
Next
The second option is not reliable when the sheets are deleted (their integer index may not be sequential then) so I would prefer the first option.
In excel 2010, I want to copy sheet 1, including all formatting and data, page setups, page breaks etc onto sheet2. In summary I want to do an exact copy of sheet1 on sheet2 through to sheet7. Ideally I want to insert a command click button on sheet1, so that once I have finished inputting data I can click the button and duplicate the information on each sheet. Any ideas?
Try this ,
Sub test()
Dim i As Integer
For i = 2 To 7
Sheets("Sheet1").Cells.Copy Sheets("Sheet" & i).Cells
Next i
End Sub
As an alternative solution I think you should create a button and assign the code below to it.
This will select all the sheets while you're on sheet1 and then whatever changes you make to sheet1 will automatically be available on all sheets instantly.
Sub test()
Dim ws As Worksheet
For Each ws In Sheets
If ws.Visible Then ws.Select
Next
End Sub