Looping through (Name) of Sheets - vba

My question is actually quite simple but I can't find a solution.
I have a lot of sheets with different names that can be modified by the user. I've given to each of those sheets a background name, so for my first two sheets, their names in my VBA project look like this:
The fact is, I want to do a macro to loop through all those particular Sheets (I have 14 of them), and I don't want to Loop through the other ones that I use for different things, like this one:
It is easy to loop through my Sheets using the names that can be modified by the user ("General" et "Heritage" in my example). Nevertheless, I want the user to be able to modify this name whenever he wants, and if he does that, my macros will not recognize the new name of the sheet. It is really important for me that the user doesn't have to push a button or use a different textbox to rename his sheet, I don't want to avoid the problem this way.
What I want is to be able to loop through the background name (S1 and S2 in my example), doing something like that (I know that the following code isn't good, but it is just to give you an example):
Sub Example1()
Dim wksht As Worksheet
For i = 1 To 14
Set wksht = "S" & i
wksht.Cells(1, 1).Value = 1
Next i
End Sub
I know that the following code works for 1 sheet:
Sub Example2()
Dim wksht As Worksheet
Set wksht = S1
wksht.Cells(1, 1).Value = 1
Next i
End Sub
The problem is S1 in my previous code isn't a string, so I can't loop using "S" & i. Is there a solution to my problem ?

You are using the sheet code name, so can do something like this. By the way, this will match S followed by a single digit which may or may not be sufficient for your needs. (By the way, it's 'through', not 'threw'.)
Sub Example1()
Dim wksht As Worksheet
For Each wksht In Worksheets
If wksht.CodeName Like "S#" Then
'do something
End If
Next wksht
End Sub

Based on my research, there does not appear a way to reference sheets based on their codename string, however, you can get the codename as a string from a sheet.
Sub test()
Dim wb As Workbook
Dim ws As Worksheet
Dim ws_temp As Worksheet
Dim i As Long
Set wb = ThisWorkbook
For i = 1 To 4
For Each ws_temp In wb.Sheets
If ws_temp.CodeName = "S" & i Then
Set ws = ws_temp
End If
Next
Debug.Print ws.Name & " " & ws.CodeName
Next
End Sub
This code will march through all of the S# sheets in order, and allow you to work with each one as ws.

Related

VBA How to fix: "Property or method is not supported with this object" when cell securing in multiple sheets

So bassicaly I want to secure a specific range within every sheet (same range always applies).
Code:
Sub desecure()
For x = 1 To ActiveWorkbook.Sheets.Count
ActiveWorkbook.Sheets(x).Range("C7:P16").Protect Password:="30713"
Next
End Sub
Sub secure()
For x = 1 To ActiveWorkbook.Sheets.Count
ActiveWorkbook.Sheets(x).Range("C7:P16").Protect Password:="30713"
Next
End Sub
It always give the error stated in the question. Anyone knows how to fix this? (or a alternative)
You can't protect a range - you set ranges to either "locked" or "unlocked" and then protect the whole sheet
To begin with, all cells are set to locked, but as the spreadsheet isn't protected this has no affect. In your case (assuming you want to be able to change other cells), you would need to unlock every other cell, lock the range you want to prevent changes in, and then protect the sheet. So
Sub secure()
dim ws as worksheet 'i change this line - typo
For each ws in worksheets
ws.cells.locked=false
ws.Range("C7:P16").locked=true
ws.Protect Password:="30713"
next ws
End Sub
Sub Desecure
dim ws as worksheet
For each ws in worksheets
ws.unprotect "30713"
Next ws
End Sub

Copy values across relative worksheets

I would like to copy a range of values from one worksheet into a specified range of another worksheet whereas values always come from the previous worksheet (in the worksheet row), even after duplicating the worksheet. I'm using the following to copy values from one worksheet to the other, which seems to work:
Sub Copy_ultimo_stock()
'copy values between two periods
Worksheets("Period2").Range("test3").Value = Worksheets("Period1").Range("test2").Value
End Sub
I had to give the range of cells a name (test2 and test3), because the macro wouldn't work if I use the actual cell range like "R10:S11". In the future however, I would just like to use the cell range as "R10:S11".
My actual problem however is the following. If I duplicate my worksheets in the future (for future periods), I want that I always copy the cell range from the previous worksheet. The way I have done it now, if I copy the worksheet period2, and call it maybe period6, it will still copy values from period1 worksheet. However, I would like that the current worksheet "n" will copy values from the range in worksheet "n-1".
I have found a somewhat similar approach that could help, but I couldn't combine both macros into one. That approach is here:
Function PrevSheet(rCell As Range)
Application.Volatile
Dim i As Integer
i = rCell.Cells(1).Parent.Index
PrevSheet = Sheets(i - 1).Range(rCell.Address)
End Function
EDIT
So you requirement is a macro that imports from "the previous sheet", so that when you click the button, the subroutine first fetches the previous from the current and accordingly fetches the values.
We will suppose that all Worksheets are named like "periodx", where x is an integer identifying the period. when we create a new worksheet copy, we need first to rename the new worksheet in the form "periodx" and then click on the button to fetch the values from the sheet "periody" where y = x-1.
Just replace your button handler Copy_ultimo_stock() with this one:
Sub Copy_ultimo_stock()
Dim wsCur As Worksheet, wsPrev As Worksheet
Set wsCur = ActiveSheet
' We will suppose that all Worksheets are named like "periodx"
' where x is an integer identifying the period
On Error Resume Next ' try fetching the previous ws as "periody" where y = x-1
Dim x As Integer: x = CInt(Mid(wsCur.Name, Len("period") + 1))
Set wsPrev = ThisWorkbook.Sheets("period" & (x - 1))
If Err.Number <> 0 Then
msgBox "Could not find the previous worksheet, Please check Worksheet names"
Exit Sub
End If
On Error GoTo 0
' Now we copy the previous values. You can customize the ranges if the design changes
wsCur.Range("D2:L8").Value = wsPrev.Range("D10:L16").Value
End Sub
Moreover, you can automate the generation of a new period worksheet by adding another button, say "Generate Next Period", that will create the new ws and give it the appropriate name. This will save the user the task of copying the sheet and renaming it. The code for the new button will be like this:
Sub create_next_period()
Dim wsCur As Worksheet, wsNext As Worksheet
Set wsCur = ActiveSheet
On Error Resume Next
Dim x As Integer: x = CInt(Mid(wsCur.Name, Len("period") + 1))
If Err.Number <> 0 Then
msgBox "Please check Worksheet name. It should be named periodx"
Exit Sub
End If
Set wsNext = ThisWorkbook.Sheets("period" & (x + 1))
If Err.Number = 0 Then
msgBox "The worksheet " & wsNext.Name & " already exists"
Exit Sub
Else
Err.Clear
wsCur.Copy After:=Worksheets(Worksheets.Count)
Set wsNext = Worksheets(Worksheets.Count)
wsNext.Name = "period" & (x + 1)
wsNext.Activate
Call Copy_ultimo_stock
End If
End Sub
When you name your cells do:
Range("whatever").name="Sheet!Name"
and not just
Range("whatever").name="Name"
==> this way you can gave the same named range on several sheets without any problem
Hope this helps.
However I wouldn't advice using too much named ranges...

I need to insert tab name in cell A1 of every tab with changing tab names

I need to open a worksheet with a fixed name and insert the name of each tab (which will change according to the current date) at the top of the sheet.
I modified some code from a previous answer and had the code working when it did not include the code to open the workbook. Now it flicks through the tabs but doesn't insert the name into Cells(1, 1) and I have no idea why. It also bugs at the end: Run-time error 91, which is less problematic but would be good to fix.
Any tips or advice much appreciated. Below is my current code:
Sub PSOPENTAB()
ChDir "G:\directory"
Workbooks.Open Filename:="G:\directory\filename.xls"
Windows("filename.xls").Activate
ActiveWorkbook.Worksheets(1).Activate
Call nametop
End Sub
Sub nametop()
Dim i As Long
With ThisWorkbook
'exit if Activesheet is the last tab
If .ActiveSheet.Index + 1 > .Worksheets.Count Then
Exit Sub
End If
For i = .ActiveSheet.Index To .Worksheets.Count - 1
.ActiveSheet.Cells(1, 1) = .Worksheets(i).Name
ActiveSheet.Next.Select
Next i
End With
End Sub
You need to reference your objects correctly.
Your problems are:
You use Thisworkbook in your nametop routine. So it will always work on the workbook containing the code.
You can change it to ActiveWorkbook but that may lead you to other problems in the future. See this cool stuff to know more about why to avoid Activeworkbook/Activesheet and the like
Applying what's discussed there, try below code:
Sub PSOPENTAB()
Dim wb As Workbook
Set wb = Workbooks.Open(Filename:="G:\directory\filename.xls")
nametop wb
End Sub
Sub nametop(wb As Workbook)
Dim ws As Worksheet
For Each ws In wb.Worksheets
ws.Cells(1, 1) = ws.Name
Next ws
End Sub
Above code adds the name of the sheet in Cell A1 of every sheet.
Is this what you're trying?

Excel VBA Create buttons to copy/rename sheets and whole workbook

I am trying to create a roadway design spreadsheet that can be used over and over again for hundreds of alignments. I got the everything working with a master sheet to be copied and two sheets used as lookup tables. I want to add two buttons in the corner that can be used to:
1) Copy the Master Sheet and rename it the alignmentname-##. This will be within the current workbook and will be used for each curve in the roadway alignment. It would be even better if there was a way to delete out these two buttons in the copied sheets.
2) A button to copy just the Master sheet, and two supplement sheets to a new workbook.
So far I have:
Sub Button10_Click()
Worksheets("Master (DO NOT MODIFY)").Copy _
Before:=ActiveWorkbook.Sheets("Master (DO NOT MODIFY)")
End Sub
It works fine for now just creating a copy of the base file, but I have not been able to rename it. The code for renaming the sheet is not working and I am not quite sure why.
Sheets(Count).Name = Range("H7").Value & "-" & Count
Where count is a public variable that goes up by one everytime a new curve is addedand H7 is the name of the alignment.
I have also played with the ActiveSheet. activesheet and Worksheets
Code for the first Button:
Public Count As Integer
Sub Button10_Click()
If Count = 0 Then
Count = 1
End If
Dim ws As Worksheet
Worksheets("Master (DO NOT MODIFY)").Copy _
Before:=ActiveWorkbook.Sheets("Master (DO NOT MODIFY)")
Set ws = ActiveSheet
ws.Name = Range("C2").Value & Count
Count = Count + 1
End Sub
Is this what you are trying? You cannot use count as the sheet is moved before the sheet and if you are incrementing the count then it will refer to the wrong sheet.
Sub Button10_Click()
Dim ws As Worksheet
Worksheets("Master (DO NOT MODIFY)").Copy _
Before:=ActiveWorkbook.Sheets("Master (DO NOT MODIFY)")
Set ws = ActiveSheet
ws.Name = Range("H7").Value & "-" & Count
End Sub
Regarding your 2nd question, you can try it like this. I am assuming that the master is not the last or the 2nd last sheet. Also there are two more sheets after the master.
Sub Button10_Click()
Dim ws As Worksheet
Dim wsMaster As Worksheet
Dim MyArray(1 To 3) As String
Dim n As Long
Set wsMaster = ThisWorkbook.Worksheets("Master (DO NOT MODIFY)")
wsMaster.Copy Before:=wsMaster
Set ws = ActiveSheet
ws.Name = Range("H7").Value & "-" & Count
n = ThisWorkbook.Sheets.Count
MyArray(1) = wsMaster.Name
MyArray(2) = ThisWorkbook.Sheets(n - 1).Name
MyArray(3) = ThisWorkbook.Sheets(n).Name
'~~> This will create a new workbook with the 3 sheets
ThisWorkbook.Sheets(MyArray).Copy
End Sub

For Each method in VBA not working

I am currently struggling to get the For Each method working in my VBA in Excel 2010.
I have used the methoed before and had no problem but for the life of me I cannot seem to get the new function I have written to work.
Here it is:
Sub A2_Color_Bob()
Dim sh As Worksheet
For Each sh In Sheets
Range("A2").Value = "Bob"
Next sh
End Sub
The reason why it's not working is that you haven't specified which sheet in this line
Range("A2").Value = "Bob"
Therefore, the default sheet will be used, i.e. the ActiveSheet
Hence, as others have also mentioned, it should be changed to
sh.Range("A2").Value = "Bob"
I think your issue is that's your Range is global, but you're trying to set a specific cell's value.
Did some checking and this works.
Sub A2_Color_Bob()
Dim sh As Worksheet
For Each sh In Sheets
sh.Cells(1, 1).Value = "bob"
Next sh
End Sub
change for each sh in sheets , to ...in worksheets
or can also do
dim i as long
for i=1 to worksheets.count
sheets(i).range("A2")=bob"
next i