Excel VBA - calling global variables by concatenated name - excel

I have these
Public Const WS1 = "SheetNameA"
Public Const WS2 = "SheetNameB"
Public Const WS3 = "SheetNameC"
Public Const WS4 = "SheetNameD"
Public Const WS5 = "SheetNameE"
Public Const WS6 = "SheetNameF"
Where SheetNameA-B-C are the names of sheets in a workbook.
And I would like to activate worksheets one after the other using a For loop 1 to 6like so:
For i = 1 to 6
Workbooks([wbkname]).Sheets(WS & i).Activate
[some more code doing stuff]
Next i
Now I know that doesn't work, I'm just trying to explain what I want.
Is that possible? To call a public constant by a concatenated name (to make that public constant string the name of the sheet we're activating)?
I hope that makes sense.
Edit: On second thought, maybe I'll just do a Select Case, which I know is not pretty, but I think, will be fine for my purpose.
For i = 1 to 6
Select Case i
Case 1
somevariable = [name of one sheet]
Case 2
somevariable = [name of another sheet]
....
End Select
Workbooks([wbkname]).Sheets(somevariable).Activate

Just use an array. First run MAIN(), then run marine():
Public WS(1 To 6) As String
Sub MAIN()
WS(1) = "SheetNameA"
WS(2) = "SheetNameB"
WS(3) = "SheetNameC"
WS(4) = "SheetNameD"
WS(5) = "SheetNameE"
WS(6) = "SheetNameF"
End Sub
Sub marine()
For i = 1 To 6
Workbooks("Book1").Sheets(WS(i)).Activate
[some more code doing stuff]
Next i
End Sub

I'm not aware of an "indirect" function in VBA, what you can do is to define a public array and store the values there, here you can get the values by index. As its not possible to define array constants in VBA you need to initialize your array before use (e.g. In the workbook's load event).

Related

Can we set sheet names and ranges as global variables?

I have three looping procedures that use a few sheets and a few ranges. I'd like to set this up so I can change the sheet names and ranges in one single place, rather than make the changes in three different places. Is that possible?
Now, I'm doing it like this.
' Loop One
Sub TestMe()
sheet_in = "Model In"
sheet_out = "Model Out"
range_in = "E10:AB300"
range_out = "E2"
Set sheet_in = Sheets(sheet_in).Range(range_in)
Set sheet_out = Sheets(sheet_out).Range(range_out)
row_count = Sheets(sheet_in).Range(range_in).Rows.Count
col_count = Sheets(sheet_in).Range(range_in).Columns.Count
For j = 1 to col_count
For i = 1 to row_count
range_out.Cells(K , 1).Value = range_in.Cells(i, j).Value
Next i
Next j
End Sub
I feel like there's go to be a better way to do this.
Consider defining constants in a dedicated module:
Public Const WS_SHEET_IN As String = "Model In"
Public Const RNG_SHEET_IN As String = "E10:AB300"
Public Const WS_SHEET_OUT As String = "Model Out"
Public Const RNG_SHEET_OUT As String = "E2"
In your regular code:
Sub TestMe()
' etc., etc.
row_count = Worksheets(WS_SHEET_IN).Range(RNG_SHEET_IN).Rows.Count
End Sub
As always though "it depends" is the answer to what is the "best" way to organize your code.
For example:
Name your worksheet code module and use that name directly instead of referring to the tab name:
InSheet.Range(RNG_SHEET_IN)
OutSheet.Range(RNG_SHEET_OUT)
Use properties or functions to return commonly-accessed objects:
Function InRange() As Range
Set InRange = thisworkbook.worksheets(WS_SHEET_IN).Range(RNG_SHEET_IN)
End function
Etc etc

VBA Excel: How to put classes into an array

Is there anyway that I can put various classes into an array so that instead of hard-coding like:
set var1 = new cls1
set var2 = new cls2
we can do:
varArr = array ( var1, var2...)
clsArr = array (cls1, cls2...)
and now I just loop thru varArr and clsArr to set new class accordingly, like:
sub setNew(x as double)
set varArr(x) = new clsArr(x)
end sub
I did try but it didn't work, please help me out
Thank you very much !
Triet (mr)
I try, but my knowledge also limited.
First of all I do not think you can put class into an array. You can put objects. I also failed to use the array() function.
Please see how I proceeded with some demonstration:
This is the class module, containing a value, the property and a primitive print sub:
Private nr As Integer 'Use as identification
Sub cPrint()
MsgBox "Object ID: " & nr
End Sub
Property Let ID(v As Integer)
nr = v
End Property
In the module in the first cycle I create the object, put the ID value. In the second one all ID values are printed. I hope you can use it for your purposes.
Sub clsTest()
Dim varArr(1 To 5) As cls1
Dim i As Integer
For i = 1 To 5
Set varArr(i) = New cls1
varArr(i).ID = i
Next
For i = 1 To 5
varArr(i).cPrint
Next
End Sub

Call constant using literals in runtime

I have declared constants like the below in the module,
Public Const strFolderA1 = "C:\ABCD\One"
Public Const strFolderA2 = "C:\ABCD\two"
I am trying to call this in a loop,
For i = 1 To 3
strFile = Dir(strFolderA & i & "\" & filenm)
Loop
The above Dir code is wrong, but I want to call the constant based on the looping integer.
Could someone help?
Please let me know if the question is not clear.
VBA does not provide any method for concatenating a string to be used as a dynamic variable name. You could create a string constant with a delimiter then split it before use.
Option Explicit
Public Const strFolderA As String = "C:\ABCD\One|C:\ABCD\Two|C:\ABCD\Three"
Sub abcs()
Dim i As Long, fldrs As Variant
fldrs = Split(strFolderA, "|")
For i = LBound(fldrs) To UBound(fldrs)
Debug.Print fldrs(i)
Next i
End Sub

Use of Combobox to populate cell with functions and external links

It is very simple but yet I can't figure it out. Maybe because it cannot be done? Regardless here we go:
I would like to use a combobox that will, when selected, input cells with text values, functions and reference to external cells.
First line of the options would be to have the name populated.
Second line is a formula that would change from course to course.
Third line would provide a cell with a reference to another cell's content from another file. So if multiple course file are used I can have one master file that if I change the content of a cell the change will reflect on all the course file cells that are referring to it once updated.
This is in crude code form what I would like it to perform.
Private Sub ComboBox1_Change()
If Me.ComboBox1.Value = "ITCourse" Then
Worksheets("PARADE STATE").Range("I1").Value = "ITCourse"
Worksheets("Data Base").Range("C1").Value = IF(V9>70,"Prep Week",IF(V9>65,"Week 1",IF(V9>60,"Week 2",IF(V9>55,"Week 3",IF(V9>50,"Week 4",IF(V9>45,"Week 5",IF(V9>40,"Week 6",IF(V9>35,"Week 7",IF(V9>30,"Week 8",IF(V9>25,"Week 9",IF(V9>20,"Week 10",IF(V9>15,"Week 11",IF(V9>10,"Week 12",IF(V9>5,"Week 13",IF(V9>0,"Week 14")))))))))))))))
Worksheets("Week 1").Range("B2").Value = 'N:\ITcourse\00 - Data Base\[ITcourse.xlsx]Sheet'!$A$3
End If
If Me.ComboBox1.Value = "HRCourse" Then
Worksheets("PARADE STATE").Range("I1").Value = "HRCourse"
Worksheets("Data Base").Range("C1").Value = IF(V9>40,"Prep Week",IF(V9>35,"Week 1",IF(V9>30,"Week 2",IF(V9>25,"Week 3",IF(V9>20,"Week 4",IF(V9>15,"Week 5",IF(V9>10,"Week 6",IF(V9>5,"Week 7",IF(V9>5,"Week 8")))))))))
Worksheets("Week 1").Range("B2").Value = 'N:\ITcourse\00 - Data Base\[HRcourse.xlsx]Sheet'!$A$3
End If
End Sub
Thank you!
You need a function that returns the number of weeks for any given course name. This function should use a Dictionary to store the information, and the dictionary may be loaded from a dedicated worksheet.
Function WeeksPerCourse(courseName As String) As Long
Static dict As Scripting.Dictionary
If dict Is Nothing Then
' Fill the dictionary here. Note that it is better
' to load the values from a dedicated, hidden worksheet
Set dict = CreateObject("Scripting.Dictionary")
dict("ITCourse") = 14
dict("HRCourse") = 8
' Etc...
End If
WeeksPerCourse = dict(courseName)
End Function
With this function available, your procedure can be simplified like follows:
Private Sub ComboBox1_Change()
Dim course As Sting: course = Trim(ComboBox1.value)
Worksheets("PARADE STATE").Range("I1").value = course
'Dim nWeek As Long
'nWeek = WeeksPerCourse(course) - Worksheets("PARADE STATE").Range("V9").value / 5
'Worksheets("Data Base").Range("C1").value = IIf(nWeek < 1, "Prep Week", "Week " & nWeek)
Worksheets("Data Base").Range("C1").Formula = "= ""Week "" & INT((WeeksPerCourse('PARADE STATE'!I1) - 'PARADE STATE'!V9)/5)"
Worksheets("Week 1").Range("B2").Formula= "='N:\ITcourse\00 - Data Base\[" & course & ".xlsx]Sheet'!$A$3"
End Sub

Userform combobox not populating on initialize

I have a user form with three comboboxes and one text box that I would like to populate with named ranges or public variables. I am working in Excel 2010 on Windows. Here is what I have:
First I run through some code that converts one worksheet into a new configuration. I then call the userform which will set up the variables necessary to update the worksheet further. I have done this on a Mac and it works, but I am transitioning this from the mac to a windows server. I thought this would be the easy part but it in not working for some reason.
Here is the code for the userform.
Public KorS As String
Public ActivityID As String
Public Stage As String
Public varsaveme As String
Private Sub ufStageDt_Initialize()
AD = varsaveme & ".xls"
duh = KorS
Set Me.tbAdName.Text = duh
Set UserForm1.Caption = AD
'Set Me.cmbLowDt.List = "AnnDt"
Set Me.cmbHighDt.List = "AnnDt"
Set Me.cmbStage.List = "Stage"
Me.cmbLowDt.List = "AnnDt"
End Sub
The public variables are present in the code on the worksheet.
Here is the code that I used on the Mac.
Private Sub UserForm_Initialize()
Ad = varsaveme & ".xls"
duh = KorS
tbAdName.Text = varsaveme
UserForm.Caption = Ad
cmbLowDt.List = Range("AnnDt").Value
cmbHighDt.List = Range("AnnDt").Value
cmbStage.List = Range("Stage").Text
End Sub
Any assistance would be greatly appreciated. I am using the ufStageDt.Show command in the vba script to bring up the userform.
Set won't work, so eliminate that. Also, List expects an array. For a single hard-coded item, use Additem.
Me.cmbHighDt.Additem "AnnDt"
EDIT: "AnnDt" is a named range:
Me.cmbHighDt.List = Application.Transpose(ActiveSheet.Range("AnnDt"))
EDIT2: For dates:
Private Sub UserForm_Initialize()
Dim i As Long
With Me.cmbHighDt
.List = Application.Transpose(ActiveSheet.Range("AnnDt"))
For i = 0 To .ListCount - 1
.List(i) = Format(.List(i), "yyyy-mm-dd")
Next i
'to get it back to a date
ActiveSheet.Range("B1") = DateValue(.List(0))
End With
End Sub

Resources