passing variable value between multiple subroutines - excel

I have a Subroutine "Days" which has a variable Days. I want to pass values form that Days variable to a different subroutine "GetDays"
For eg:
Sub Day()
Dim Days() as variant
Days = Array(1,3,5,7,10,11)
End Sub
Sub GetDay()
'How do I get the values of Days here?
End Sub

Not completely sure I understand what you're after, but my best guess is that you want to set up a "DayClass" object that both holds the days values and returns them to other functions when they're needed:
(1) in the VBA editor, insert a CLASS module
(2) in the properties window for this module, change the name to (say) DayClass (overriding the default name "Class1".)
(3) put this code into the DayClass module:
Private mDays As Variant ' member variable to hold the days array
' initialization method to populate the array
Private Sub Class_Initialize()
mDays = Array(1, 3, 5, 7, 10, 11)
End Sub
' little function to return a particular value from the array
Public Property Get Day(i As Long)
Day = mDays(i)
End Property
(4) To see the code above in action, insert a regular MODULE and put this little function in it, which may be invoked from the formula bar (if you want):
Public Function GetDays(i As Long)
Dim DC As New DayClass ' DC is dim'd of type DayClass
' so via DC you can get at whatever is in there
GetDays = DC.Day(i) ' this function returns the i'th value of the
' array in DayClass, via DayClass's "Get Day" property
End Function
(5) Since "GetDays" is a public function in a regular code module, you can test this out by entering the following formula into any spreadsheet cell:
=GetDays(3)
cell result = 7

Related

Using VBA in Excel - Static variable not retained when Multipage object has change event (changing pages)

I am having trouble with losing static variables within an Excel user form.
I have been working on a routine for excel. I am a (very) novice coder.
I am attempting to populate a cell range to an array. I have been able to do this without issue.
However, when I attempt to store the array as a *static * variable, the variable is not retained for as long as I want it to be.
I think the problem occurs when another page is selected in the multipage, the static variable is cleared.
Code is something like this:
Sub UserForm_Initialize ()
static myArray () as variant
dim myRange as range
set myRange = [namedrange]
myArray=myRange
msgbox myArray(0,0) 'this works fine
call OtherSub
end sub
sub OtherSub ()
msgbox myArray(0,0) 'this returns a blank
end sub
The first sub of code shows the array element just fine. The array element is blank in the second sub.
I have tried:
Declaring the array as a public variable, but this returns an error (I think that variables within user forms are private by default and cannot be changed).
using a very small variable (a simple string)
writing code in a module before opening the user form (variable is not retained).
I am aware that I can just write data to a cell range, but this would defeat the purpose. I was hoping to avoid multiple instances of reading large arrays from the worksheet.
This might explain it a bit clearer. Moving MyArray outside of the Procedure will set it's scope to a Module Level, making it usable through other subs within that module. You will generally want to keep the scope of your variables to the lowest level required. The other option would be to pass your variable as a parameter to your other procedure.
Option Explicit
Dim MyArray() As Variant ' Private Module Level Scope
Public ExampleVariable As String ' Public Module Level Scope (Not required, just showing an example.)
Sub UserForm_Initialize()
Dim myRange As Range ' Procedure Level Scope
Set myRange = [namedrange]
MyArray = myRange
MsgBox MyArray(0, 0) 'this works fine
Call OtherSub
End Sub
Sub OtherSub()
MsgBox MyArray(0, 0) 'this returns a blank
End Sub

How to populate combobox values from textbox text in excel vba form

I have a problem in my VBA form in Excel and I'm trying to filter the value of a combobox using VLOOKUP from whatever I type in the textbox. How do I achieve this?
My code is:
Private Sub btnTemplateSearch_Click()
Dim filterInfo As Range
Set filterInfo = Worksheets("InfoDump").Range("E2:F46")
txtTemplateFilter.Text = filterInfo.Columns(2).Value
Me.cboTemplateType.List = Application.WorksheetFunction.VLookup(Me.txtTemplateFilter.Text, filterInfo,2,True)
Below is an example of a block of code that can be used to filter the list of ComboBox entries. I decided to Dim an array variable ListForComboBox at the module level such that all procedures in the module can access it. It gets populated at the form's init event by calling LoadListForComboboxArray. You can make changes to this procedure to update the range of input values or any other changes. The combobox's list property is set to this array.
Here's the caveat: you may want to consider tuning the below for performance. I included a textbox, and in the change event, I make a call to set the global array to a filtered version of the original array, based on textbox value. That means that the code will filter the array everytime you type a letter (so if you type "ABC", it will filter three times, creating a new array each time). You may want to assign that function to a different event (textbox exit, maybe) such that the code only fires once you leave the text box, and only once.
Let me know if you have trouble adapting the code:
Dim ListForCombobox() As String
Private Sub TextBox1_Change()
Me.ComboBox1.List = Filter(ListForCombobox, Me.TextBox1.Value)
Debug.Print "CALLED"
End Sub
Private Sub UserForm_Initialize()
LoadListForComboboxArray
Me.ComboBox1.List = ListForCombobox
End Sub
Private Sub LoadListForComboboxArray()
Dim rng As Range
Set rng = Sheets("Sheet1").Range("A1:A11")
ReDim ListForCombobox(1 To rng.Rows.Count)
For i = 1 To rng.Rows.Count
ListForCombobox(i) = rng(i).Value
Next i
Debug.Print ListForCombobox(1)
End Sub

Excel global variable reseted to empty when navigating through workbooks

I encounter a weird problem that I believe is related to Excel behavior, rather than to my code.
I have a global variable named "numEtape", which is an integer. My code consists in several steps where the user has to type data on a sheet, then press a button which saves the data in an array and increments the "numEtape", before going to the next step.
The code (simplified) looks like this :
Dim numEtape As Integer
Sub AjoutEssai()
numEtape = 2
UFPreAjoutInfos.Show 'Unrelated Userform that asks user for more informations, but doesn't modify "numEtape" or call any other macro
Call InterfaceFiller
End Sub
Sub InterfaceFiller()
Dim rangedubtn As Range
Dim btnPrecedent As Button
Select Case numEtape
Case 2
'Change value of some cells
Case 3
'Change value of some cells
Case 4
'Change value of some cells
Case Is >= 5
'Change value of some cells
Case Else
Debug.Print "Error"
End Select
Set rangedubtn = Sheets("Interface").Range("M3")
Set btnPrecedent = Sheets("Interface").Buttons.Add(rangedubtn.Left, rangedubtn.Top,rangedubtn.Width, rangedubtn.Height)
With btnPrecedent
.OnAction = "mSuivant"
.Caption = "Suivant"
.Name = "btnSuivant"
End With
End Sub
Sub mSuivant()
numEtape = numEtape + 1
Call InterfaceFiller
End Sub
I don't think the code itself is important, what I can expect from it, since I first call AjoutEssai(), is for numEtape to always be greater than 2.
However, when during the steps the user opens and close other excel/office files (that don't have any vba code/macros in it), excel seems to empty numEtape, which makes the Select Case go to the Case Else.
When does excel remove global variables from memory, and is there a way to prevent this behavior from happening?
Public numEtape As Long
A viable option is to use the word public like public numEtape As Long.
Then the variable will be saving its value for as long as the Excel workbook is opened. In older versions of VBA the word was Global (What is the difference between Dim, Global, Public, and Private as Modular Field Access Modifiers?)
Dim numEtape As Long
For using Dim outside of Sub or Function, the variable will be emptied, after the code is over. Take this snippet only:
Dim numEtape As Long
Sub MainTest()
numEtape = 23
End Sub
Once you run it and you hit End Sub the variable would be emptied as well. Check after running the MainTest():
Sub PrintingVariable()
Debug.Print numEtape
End Sub
If you want to save the value, there are 2 basic ways that work:
Write the value in an excel cell
Write the value in a database

VBA Dependent Combobox

I have 3 combo boxes which are dependent with each other. List on cmb2 depends on the value on cmb1. cmb3 list depends on cmb2 value.
My problem is, when I remove/delete the values on all combo boxes, when I click cmb2, it still shows the list of the last value chosen on cmb1 & same goes with cmb3.
What's the code to show it empty if the combo box where it's dependent to doesn't have any value?
EDIT: I think based on added information in the comment that you should look to encapsulate the logic in sub procedures and functions. To best do so, there should be some logic between named ranges and the values in the combobox.
In the below example, I created a function to handle conversions from the value in the independent combobox and the named ranges. You can supply your own connector, but I assumed that any space will be changed to an underscore (so, 'Account Information' will be replaced with 'Account_Information').
Next a subprocedure checks to confirm that the named range exists in the workbook that matches the converted value in the independent combobox. If so, the dependent box takes on that named range as its List property. If not, the dependent combobox is cleared.
The benefit to using this type of a system is that it could be repeated for other comboboxes without rewriting code. See below code and let us know if you need added help.
Private Sub UserForm_Initialize()
With Me.ComboBox1
.AddItem "Account Information"
.AddItem "Other Stuff"
End With
End Sub
Private Sub ComboBox1_Change()
With Me
LoadDependentCBO Me.ComboBox1, Me.ComboBox2
End With
End Sub
Private Function ConvertValueToNamedRange(sValue As String, sConnector As String) As String
'This function takes values in the combobox and converts them to named ranges
'The spaces are replaced with whichever connector is supplied to the function
'NOTE: I created a separate function even though this only uses a built-in function
'in case more implementation code is needed
ConvertValueToNamedRange = Replace(sValue, " ", sConnector)
End Function
Private Sub LoadDependentCBO(cboIndependent As ComboBox, cboDependent As ComboBox)
'This code looks to see if there is a match between the value of the independent combobox
'and a named range in the workbook. If not, the dependent combobox is set to be empty
Dim sTemp As String
Dim rNamedRange As Range
sTemp = ""
On Error Resume Next
sTemp = Names.Item(ConvertValueToNamedRange(cboIndependent.Value, "_")).Name
On Error GoTo 0
If sTemp = "" Then
'There is no matching named range so clear the dependent combobox
cboDependent.Clear
Else
cboDependent.List = Range(sTemp).Value
End If
End Sub
OLD POST:
The code ComboBox1.ListIndex = -1 will set the combo box to empty (change the name of the box to suit). The logic to do so depends on more details. Let us know if you need help with implementation.

VBA variables and offset

Im having trouble takign my assigned variable and offseting it. What am I doing wrong?
Public Sub SampleBox_Change()
Dim str As Integer
If (SampleBox.ListIndex > -1) Then
str = SampleBox.List(SampleBox.ListIndex)
End If
End Sub
Public Sub Samplesdel(str As Integer)
Range(Range("BA1").EntireColumn, Range("BA1").Offset(0, -str).EntireColumn).Select
End Sub
Public Sub CommandButton1_Click()
Application.Run "Samplesdel"
End Sub
So the variable (str) is a whole number. I would like to use this number to select a certain number of columns (from BA1 to "left however many columns valued as str"). so if the user selects 8 i would like to select BA1 and left 8 columns.
The combobox is in a userform where the code for the assigned variable is set.
I would like to use the assigned variable in a macro (where i used the select function).
so the variable str gets assigned from a userform combobox. I would then like to pass this variable to a macro where i use it in the offset function.
I just used your snippets of code here, I'll assume you know what you're trying to accomplish with this. As mentioned in another answer, I think it's an issue of scope; it doesn't seem like there's a good reason you can't combine your statements as follows:
Public Sub SampleBox_Change()
Dim str As Integer
If (SampleBox.ListIndex > -1) Then
Range(Range("BA1").EntireColumn, Range("BA1").Offset(0, SampleBox.ListIndex).EntireColumn).Select
End If
End Sub
To add some unsolicited feedback, naming a variable that is an integer "str" will be very confusing to anyone else that has to read your code, the name "str" implies "string", a different data type.
James, you are setting the value of str here correct?
Public Sub SampleBox_Change()
Dim str As Integer
If (SampleBox.ListIndex > -1) Then
str = SampleBox.List(SampleBox.ListIndex)
End If
End Sub
The scope for str will only be this function and it will not be able to be accessed by any other function.
What value are you passing to Samplesdel as the parameter?
Application.Run "Samplesdel"

Resources